bool StyleInjector::launch(const QStringList &programAndArgs,
                          const QString &probeDll, const QString &probeFunc)
{
  QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
  env.insert("GAMMARAY_STYLEINJECTOR_PROBEDLL", probeDll);
  env.insert("GAMMARAY_STYLEINJECTOR_PROBEFUNC", probeFunc);

  QString qtPluginPath = env.value("QT_PLUGIN_PATH");
  if (!qtPluginPath.isEmpty()) {
    qtPluginPath.append(":");
  }
  qtPluginPath.append(GAMMARAY_LIB_INSTALL_DIR "/qt4/plugins");
  env.insert("QT_PLUGIN_PATH", qtPluginPath);

  InteractiveProcess proc;
  proc.setProcessEnvironment(env);
  proc.setProcessChannelMode(QProcess::ForwardedChannels);

  QStringList args = programAndArgs;

  if (env.value("GAMMARAY_GDB").toInt()) {
    QStringList newArgs;
    newArgs << "gdb" << "--eval-command" << "run" << "--args";
    newArgs += args;
    args = newArgs;
  } else if (env.value("GAMMARAY_MEMCHECK").toInt()) {
    QStringList newArgs;
    newArgs << "valgrind" << "--tool=memcheck" << "--track-origins=yes" << "--num-callers=25";
    newArgs += args;
    args = newArgs;
  } else if (env.value("GAMMARAY_HELGRIND").toInt()) {
    QStringList newArgs;
    newArgs << "valgrind" << "--tool=helgrind";
    newArgs += args;
    args = newArgs;
  }

  const QString program = args.takeFirst();
  args << QLatin1String("-style") << QLatin1String("gammaray-injector");
  proc.start(program, args);
  proc.waitForFinished(-1);

  mExitCode = proc.exitCode();
  mProcessError = proc.error();
  mExitStatus = proc.exitStatus();
  mErrorString = proc.errorString();

  return mExitCode == EXIT_SUCCESS && mExitStatus == QProcess::NormalExit;
}
Example #2
0
bool ProcessInjector::launchProcess(const QStringList& programAndArgs, const QProcessEnvironment& env)
{
  InteractiveProcess proc;
  proc.setProcessEnvironment(env);
  proc.setProcessChannelMode(QProcess::ForwardedChannels);

  QStringList args = programAndArgs;

  if (env.value("GAMMARAY_GDB").toInt()) {
    QStringList newArgs;
    newArgs << "gdb";
#ifndef Q_OS_MAC
    newArgs << "--eval-command" << "run";
#endif
    newArgs << "--args";
    newArgs += args;
    args = newArgs;
  } else if (env.value("GAMMARAY_MEMCHECK").toInt()) {
    QStringList newArgs;
    newArgs << "valgrind"
            << "--tool=memcheck"
            << "--track-origins=yes"
            << "--num-callers=25"
            << "--leak-check=full";
    newArgs += args;
    args = newArgs;
  } else if (env.value("GAMMARAY_HELGRIND").toInt()) {
    QStringList newArgs;
    newArgs << "valgrind" << "--tool=helgrind";
    newArgs += args;
    args = newArgs;
  }

  const QString program = args.takeFirst();
  proc.start(program, args);
  proc.waitForFinished(-1);

  mExitCode = proc.exitCode();
  mProcessError = proc.error();
  mExitStatus = proc.exitStatus();
  mErrorString = proc.errorString();

  if (mProcessError == QProcess::FailedToStart) {
    mErrorString.prepend(QString("Could not start '%1': ").arg(program));
  }

  return mExitCode == EXIT_SUCCESS && mExitStatus == QProcess::NormalExit
          && mProcessError == QProcess::UnknownError;
}
bool ProcessInjector::launchProcess(const QStringList& programAndArgs, const QProcessEnvironment& env)
{
    InteractiveProcess proc;
    proc.setProcessEnvironment(env);
    proc.setProcessChannelMode(QProcess::ForwardedChannels);

    QStringList args = programAndArgs;

    if (!env.value("GAMMARAY_TARGET_WRAPPER").isEmpty()) {
        const QString fullWrapperCmd = env.value("GAMMARAY_TARGET_WRAPPER");
        // ### TODO properly handle quoted arguments!
        QStringList newArgs = fullWrapperCmd.split(' ');
        newArgs += args;
        args = newArgs;
        qDebug() << "Launching with target wrapper:" << args;
    } else if (env.value("GAMMARAY_GDB").toInt()) {
        QStringList newArgs;
        newArgs << "gdb";
#ifndef Q_OS_MAC
        newArgs << "--eval-command" << "run";
#endif
        newArgs << "--args";
        newArgs += args;
        args = newArgs;
    }

    const QString program = args.takeFirst();
    proc.start(program, args);
    proc.waitForFinished(-1);

    mExitCode = proc.exitCode();
    mProcessError = proc.error();
    mExitStatus = proc.exitStatus();
    mErrorString = proc.errorString();

    if (mProcessError == QProcess::FailedToStart) {
        mErrorString.prepend(QString("Could not start '%1': ").arg(program));
    }

    return mExitCode == EXIT_SUCCESS && mExitStatus == QProcess::NormalExit
           && mProcessError == QProcess::UnknownError;
}
Example #4
0
int main (int argc, char *argv[]) {
	QApplication app (argc, argv);
	QStringList args = app.arguments ();
	if (!args.isEmpty ()) args.pop_front ();	// The command itself
	qputenv ("DESKTOP_STARTUP_ID", qgetenv ("STARTUP_ID_COPY"));	// for startup notifications (set via rkward.desktop)
	qputenv ("STARTUP_ID_COPY", "");

	// Parse arguments that need handling in the wrapper
	bool usage = false;
	QStringList debugger_args;
	QStringList file_args;
	bool reuse = false;
	bool warn_external = true;
	QString r_exe_arg;
	int debug_level = 2;

	for (int i=0; i < args.size (); ++i) {
		if (args[i] == "--debugger") {
			args.removeAt (i);
			while (i < args.size ()) {
				QString arg = args.takeAt (i);
				if (arg == "--") break;
				debugger_args.append (arg);
			}
			if (debugger_args.isEmpty ()) usage = true;
		} else if (args[i] == "--r-executable") {
			if ((i+1) < args.size ()) {
				r_exe_arg = args.takeAt (i + 1);
			} else usage = true;
			args.removeAt (i);
			--i;
		} else if (args[i] == "--debug-level") {
			if ((i+1) < args.size ()) {
				debug_level = args[i+1].toInt ();
			}
		} else if (args[i] == "--reuse") {
			reuse = true;
		} else if (args[i] == "--nowarn-external") {
			warn_external = false;
		} else if (args[i].startsWith ("--")) {
			// all RKWard and KDE options (other than --reuse) are of the for --option <value>. So skip over the <value>
			i++;
		} else {
			QUrl url (args[i]);
			if (url.isRelative ()) {
				file_args.append (QDir::current ().absoluteFilePath (url.toLocalFile ()));
			} else {
				file_args.append (args[i]);
			}
		}
	}

	if (reuse) {
		if (!QDBusConnection::sessionBus ().isConnected ()) {
			if (debug_level > 2) qDebug ("Could not connect to session dbus");
		} else {
			QDBusInterface iface (RKDBUS_SERVICENAME, "/", "", QDBusConnection::sessionBus ());
			if (iface.isValid ()) {
				QDBusReply<void> reply = iface.call ("openAnyUrl", file_args, warn_external);
				if (!reply.isValid ()) {
					if (debug_level > 2) qDebug ("Error while placing dbus call: %s", qPrintable (reply.error ().message ()));
					return 1;
				}
				return 0;
			}
		}
	}

	// MacOS may need some path adjustments, first
#ifdef Q_WS_MAC
	QString oldpath = qgetenv ("PATH");
	if (!oldpath.contains (INSTALL_PATH)) {
		//ensure that PATH is set to include what we deliver with the bundle
		qputenv ("PATH", QString ("%1/bin:%1/sbin:%2").arg (INSTALL_PATH).arg (oldpath).toLocal8Bit ());
		if (debug_level > 3) qDebug ("Adjusting system path to %s", qPrintable (qgetenv ("PATH")));
	}
	// ensure that RKWard finds its own packages
	qputenv ("R_LIBS", R_LIBS);
	QProcess::execute ("launchctl", QStringList () << "load" << "-w" << INSTALL_PATH "/Library/LaunchAgents/org.freedesktop.dbus-session.plist");
#endif

	// Locate KDE and RKWard installations
	QString kde4_config_exe = findExeAtPath ("kde4-config", QDir::currentPath ());
	if (kde4_config_exe.isNull ()) kde4_config_exe = findExeAtPath ("kde4-config", app.applicationDirPath ());
	if (kde4_config_exe.isNull ()) kde4_config_exe = findExeAtPath ("kde4-config", QDir (app.applicationDirPath ()).filePath ("KDE/bin"));
	if (kde4_config_exe.isNull ()) {
#ifdef Q_WS_WIN
	QStringList syspath = QString (qgetenv ("PATH")).split (';');
#else
	QStringList syspath = QString (qgetenv ("PATH")).split (':');
#endif
		for (int i = 0; i < syspath.size (); ++i) {
			kde4_config_exe = findExeAtPath ("kde4-config", syspath[i]);
			if (!kde4_config_exe.isNull ()) break;
		}
	}

	if (kde4_config_exe.isNull ()) {
		QMessageBox::critical (0, "Could not find KDE installation", "The KDE installation could not be found (kde4-config). When moving / copying RKWard, make sure to copy the whole application folder, or create a shorcut / link, instead.");
		exit (1);
	}

	QDir kde_dir (QFileInfo (kde4_config_exe).absolutePath ());
	kde_dir.makeAbsolute ();
	QString kde_dir_safe_path = quoteCommand (kde_dir.path ());
#ifdef Q_WS_WIN
	QString kdeinit4_exe = findExeAtPath ("kdeinit4", kde_dir.path ());
	qputenv ("PATH", QString (kde_dir_safe_path + ';' + qgetenv ("PATH")).toLocal8Bit ());
	if (debug_level > 3) qDebug ("Adding %s to the system path", qPrintable (kde_dir_safe_path));
#endif
	// important if RKWard is not in KDEPREFIX/bin but e.g. KDEPREFIX/lib/libexec
	qputenv ("RKWARD_ENSURE_PREFIX", kde_dir_safe_path.toLocal8Bit ());
	if (debug_level > 3) qDebug ("Setting environment variable RKWARD_ENSURE_PREFIX=%s", qPrintable (kde_dir_safe_path));

	QString rkward_frontend_exe = findRKWardAtPath (app.applicationDirPath ());	// this is for running directly from a build tree
#ifdef Q_WS_MAC
	if (rkward_frontend_exe.isNull ()) rkward_frontend_exe = findRKWardAtPath (app.applicationDirPath () + "/rkward.frontend.app/Contents/MacOS"); 	// this is for running directly from a build tree
#endif
	if (rkward_frontend_exe.isNull ()) rkward_frontend_exe = findRKWardAtPath (RKWARD_FRONTEND_LOCATION);
	if (rkward_frontend_exe.isNull ()) rkward_frontend_exe = findRKWardAtPath (kde_dir.absoluteFilePath ("bin"));
	if (rkward_frontend_exe.isNull ()) rkward_frontend_exe = findRKWardAtPath (kde_dir.absoluteFilePath ("../lib/libexec"));

	if (rkward_frontend_exe.isNull ()) {
		QMessageBox::critical (0, "RKWard frontend binary missing", "RKWard frontend binary could not be found. When moving / copying RKWard, make sure to copy the whole application folder, or create a shorcut / link, instead.");
		exit (1);
	}

	if (usage) {
		QProcess::execute (rkward_frontend_exe, QStringList ("--help"));
		exit (1);
	}

#ifdef Q_WS_WIN
	// Explicit initialization of KDE, in case Windows 7 asks for admin privileges
	if (kdeinit4_exe.isNull ()) {
		kdeinit4_exe = findExeAtPath ("kdeinit4", QFileInfo (rkward_frontend_exe).absolutePath ());
	}
	if (!kdeinit4_exe.isNull ()) QProcess::execute (kdeinit4_exe, QStringList ());
#endif

	// Look for R:
	//- command line parameter
	//- Specified in cfg file next to rkward executable
	//- compile-time default
	QString r_exe = r_exe_arg;
	if (!r_exe.isNull ()) {
		if (!QFileInfo (r_exe).isExecutable ()) {
			QMessageBox::critical (0, "Specified R executable does not exist", QString ("The R executable specified on the command line (%1) does not exist or is not executable.").arg (r_exe));
			exit (1);
		}
		if (debug_level > 3) qDebug ("Using R specified on command line");
	} else {
		QFileInfo frontend_info (rkward_frontend_exe);
		QDir frontend_path = frontend_info.absoluteDir ();
		QFileInfo rkward_ini_file (frontend_path.absoluteFilePath ("rkward.ini"));
		if (rkward_ini_file.isReadable ()) {
			QSettings rkward_ini (rkward_ini_file.absoluteFilePath (), QSettings::IniFormat);
			r_exe = rkward_ini.value ("R executable").toString ();
			if (!r_exe.isNull ()) {
				if (QDir::isRelativePath (r_exe)) {
					r_exe = frontend_path.absoluteFilePath (r_exe);
				}
				if (!QFileInfo (r_exe).isExecutable ()) {
					QMessageBox::critical (0, "Specified R executable does not exist", QString ("The R executable specified in the rkward.ini file (%1) does not exist or is not executable.").arg (rkward_ini_file.absoluteFilePath ()));
					exit (1);
				}
			}
			if (debug_level > 3) qDebug ("Using R as configured in config file %s", qPrintable (rkward_ini_file.absoluteFilePath ()));
		}
		if (r_exe.isNull ()) {
			r_exe = R_EXECUTABLE;
			if (!QFileInfo (r_exe).isExecutable ()) {
				QMessageBox::critical (0, "Specified R executable does not exist", QString ("The R executable specified at compile time (%1) does not exist or is not executable. Probably the installation of R has moved. You can use the command line parameter '--R', or supply an rkward.ini file to specify the new location.").arg (r_exe));
				exit (1);
			}
			if (debug_level > 3) qDebug ("Using R as configured at compile time");
		}
	}

	qputenv ("R_BINARY", r_exe.toLocal8Bit ());
	QStringList call_args ("CMD");
	call_args.append (debugger_args);
	call_args.append (quoteCommand (rkward_frontend_exe));

	if (!args.isEmpty ()) {
		// NOTE: QProcess quotes its arguments, *but* properly passing all spaces and quotes through the R CMD wrapper, seems near(?) impossible on Windows. Instead, we use percent encoding, internally.
		for (int i = 0; i < args.size (); ++i) {
			call_args.append (QString::fromUtf8 (QUrl::toPercentEncoding (args[i], QByteArray (), " \"")));
		}
	}

	if (debug_level > 2) qDebug ("Starting frontend: %s %s", qPrintable (r_exe), qPrintable (call_args.join (" ")));

	InteractiveProcess proc;
#ifdef Q_WS_WIN
	if (debugger_args.isEmpty ()) {
		// start _without_ opening an annoying console window
		QTemporaryFile *vbsf = new QTemporaryFile (QDir::tempPath () + "/rkwardlaunchXXXXXX.vbs");
		vbsf->setAutoRemove (false);
		if (vbsf->open ()) {
			QTextStream vbs (vbsf);
			vbs << "Dim WinScriptHost\r\nSet WinScriptHost = CreateObject(\"WScript.Shell\")\r\nWinScriptHost.Run \"" << quoteCommand (r_exe);
			for (int i = 0;  i < call_args.length (); ++i) {
				vbs << " " << call_args[i];
			}
			vbs << "\", 0\r\nSet WomScriptHost = Nothing\r\n";
			vbsf->close ();
			QString filename = vbsf->fileName ();
			delete (vbsf);  // somehow, if creating vbsf on the stack, we cannot launch it, because "file is in use by another process", despite we have closed it.
			proc.start ("WScript.exe", QStringList (filename));
			bool ok = proc.waitForFinished (-1);
			if (proc.exitCode () || !ok) {
				QMessageBox::critical (0, "Error starting RKWard", QString ("Starting RKWard failed with error \"%1\"").arg (proc.errorString ()));
			}
			QFile (filename).remove ();
			return (0);
		}
	}
	// if that did not work or not on windows:
#endif
	proc.setProcessChannelMode (QProcess::ForwardedChannels);
	proc.start (quoteCommand (r_exe), call_args);
	bool ok = proc.waitForFinished (-1);
	if (proc.exitCode () || !ok) {
		QMessageBox::critical (0, "Error starting RKWard", QString ("Starting RKWard failed with error \"%1\"").arg (proc.errorString ()));
	}

	return (0);
}
Example #5
0
bool PreloadInjector::launch(const QStringList &programAndArgs,
                            const QString &probeDll,
                            const QString &probeFunc)
{
  Q_UNUSED(probeFunc);

  QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
#ifdef Q_OS_MAC
  env.insert("DYLD_FORCE_FLAT_NAMESPACE", QLatin1String("1"));
  env.insert("DYLD_INSERT_LIBRARIES", probeDll);
  env.insert("GAMMARAY_UNSET_DYLD", "1");
#else
  env.insert("LD_PRELOAD", probeDll);
  env.insert("GAMMARAY_UNSET_PRELOAD", "1");

  PreloadCheck check;
  bool success = check.test("qt_startup_hook");
  if (!success) {
    mExitCode = 1;
    mErrorString = check.errorString();
    return false;
  }
#endif

  InteractiveProcess proc;
  proc.setProcessEnvironment(env);
  proc.setProcessChannelMode(QProcess::ForwardedChannels);

  QStringList args = programAndArgs;

  if (env.value("GAMMARAY_GDB").toInt()) {
    QStringList newArgs;
    newArgs << "gdb";
#ifndef Q_OS_MAC
    newArgs << "--eval-command" << "run";
#endif
    newArgs << "--args";
    newArgs += args;
    args = newArgs;
  } else if (env.value("GAMMARAY_MEMCHECK").toInt()) {
    QStringList newArgs;
    newArgs << "valgrind"
            << "--tool=memcheck"
            << "--track-origins=yes"
            << "--num-callers=25"
            << "--leak-check=full";
    newArgs += args;
    args = newArgs;
  } else if (env.value("GAMMARAY_HELGRIND").toInt()) {
    QStringList newArgs;
    newArgs << "valgrind" << "--tool=helgrind";
    newArgs += args;
    args = newArgs;
  }

  const QString program = args.takeFirst();
  proc.start(program, args);
  proc.waitForFinished(-1);

  mExitCode = proc.exitCode();
  mProcessError = proc.error();
  mExitStatus = proc.exitStatus();
  mErrorString = proc.errorString();

  return mExitCode == EXIT_SUCCESS && mExitStatus == QProcess::NormalExit
          && mProcessError == QProcess::UnknownError;
}