From 4d0caf6254fdb18f4626a3c7937e64422b40d40c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 5 Jan 2016 07:32:52 +0100 Subject: GH-1389 wrap QDesktopServices and QProcess::startDetached Essentially do not pass some environment variables to subprocesses: * LD_PRELOAD * LD_LIBRARY_PATH * LD_DEBUG * QT_PLUGIN_PATH * QT_FONTPATH --- logic/CMakeLists.txt | 4 ++ logic/DesktopServices.cpp | 149 +++++++++++++++++++++++++++++++++++++++++++++ logic/DesktopServices.h | 37 +++++++++++ logic/FileSystem.cpp | 20 +----- logic/FileSystem.h | 6 -- logic/tools/MCEditTool.cpp | 4 +- 6 files changed, 194 insertions(+), 26 deletions(-) create mode 100644 logic/DesktopServices.cpp create mode 100644 logic/DesktopServices.h (limited to 'logic') diff --git a/logic/CMakeLists.txt b/logic/CMakeLists.txt index 0398cffe..9a87dcab 100644 --- a/logic/CMakeLists.txt +++ b/logic/CMakeLists.txt @@ -32,8 +32,12 @@ set(LOGIC_SOURCES # JSON parsing helpers Json.h Json.cpp + FileSystem.h FileSystem.cpp + DesktopServices.h + DesktopServices.cpp + Exception.h # RW lock protected map diff --git a/logic/DesktopServices.cpp b/logic/DesktopServices.cpp new file mode 100644 index 00000000..3154ea01 --- /dev/null +++ b/logic/DesktopServices.cpp @@ -0,0 +1,149 @@ +#include "DesktopServices.h" +#include +#include +#include +#include + +/** + * This shouldn't exist, but until QTBUG-9328 and other unreported bugs are fixed, it needs to be a thing. + */ +#if defined(Q_OS_LINUX) + +#include +#include +#include +#include + +template +bool IndirectOpen(T callable, qint64 *pid_forked = nullptr) +{ + auto pid = fork(); + if(pid_forked) + { + if(pid > 0) + *pid_forked = pid; + else + *pid_forked = 0; + } + if(pid == -1) + { + qWarning() << "IndirectOpen failed to fork: " << errno; + return false; + } + // child - do the stuff + if(pid == 0) + { + // unset all this garbage so it doesn't get passed to the child process + qunsetenv("LD_PRELOAD"); + qunsetenv("LD_LIBRARY_PATH"); + qunsetenv("LD_DEBUG"); + qunsetenv("QT_PLUGIN_PATH"); + qunsetenv("QT_FONTPATH"); + + // open the URL + auto status = callable(); + + // detach from the parent process group. + setsid(); + + // die. now. do not clean up anything, it would just hang forever. + _exit(status ? 0 : 1); + } + else + { + //parent - assume it worked. + int status; + while (waitpid(pid, &status, 0)) + { + if(WIFEXITED(status)) + { + return WEXITSTATUS(status) == 0; + } + if(WIFSIGNALED(status)) + { + return false; + } + } + return true; + } +} +#endif + +namespace DesktopServices { +bool openDirectory(const QString &path, bool ensureExists) +{ + qDebug() << "Opening directory" << path; + QDir parentPath; + QDir dir(path); + if (!dir.exists()) + { + parentPath.mkpath(dir.absolutePath()); + } + auto f = [&]() + { + return QDesktopServices::openUrl(QUrl::fromLocalFile(dir.absolutePath())); + }; +#if defined(Q_OS_LINUX) + return IndirectOpen(f); +#else + return f(); +#endif +} + +bool openFile(const QString &path) +{ + qDebug() << "Opening file" << path; + auto f = [&]() + { + return QDesktopServices::openUrl(QUrl::fromLocalFile(path)); + }; +#if defined(Q_OS_LINUX) + return IndirectOpen(f); +#else + return f(); +#endif +} + +bool openFile(const QString &application, const QString &path, const QString &workingDirectory, qint64 *pid) +{ + qDebug() << "Opening file" << path << "using" << application; +#if defined(Q_OS_LINUX) + // FIXME: the pid here is fake. So if something depends on it, it will likely misbehave + return IndirectOpen([&]() + { + return QProcess::startDetached(application, QStringList() << path, workingDirectory); + }, pid); +#else + return QProcess::startDetached(application, QStringList() << path, workingDirectory, pid); +#endif +} + +bool run(const QString &application, const QStringList &args, const QString &workingDirectory, qint64 *pid) +{ + qDebug() << "Running" << application << "with args" << args.join(' '); +#if defined(Q_OS_LINUX) + // FIXME: the pid here is fake. So if something depends on it, it will likely misbehave + return IndirectOpen([&]() + { + return QProcess::startDetached(application, args, workingDirectory); + }, pid); +#else + return QProcess::startDetached(application, args, workingDirectory, pid); +#endif +} + +bool openUrl(const QUrl &url) +{ + qDebug() << "Opening URL" << url.toString(); + auto f = [&]() + { + return QDesktopServices::openUrl(url); + }; +#if defined(Q_OS_LINUX) + return IndirectOpen(f); +#else + return f(); +#endif +} + +} diff --git a/logic/DesktopServices.h b/logic/DesktopServices.h new file mode 100644 index 00000000..1e67e4cb --- /dev/null +++ b/logic/DesktopServices.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include "multimc_logic_export.h" + +/** + * This wraps around QDesktopServices and adds workarounds where needed + * Use this instead of QDesktopServices! + */ +namespace DesktopServices +{ + /** + * Open a file in whatever application is applicable + */ + MULTIMC_LOGIC_EXPORT bool openFile(const QString &path); + + /** + * Open a file in the specified application + */ + MULTIMC_LOGIC_EXPORT bool openFile(const QString &application, const QString &path, const QString & workingDirectory = QString(), qint64 *pid = 0); + + /** + * Run an application + */ + MULTIMC_LOGIC_EXPORT bool run(const QString &application,const QStringList &args, const QString & workingDirectory = QString(), qint64 *pid = 0); + + /** + * Open a directory + */ + MULTIMC_LOGIC_EXPORT bool openDirectory(const QString &path, bool ensureExists = false); + + /** + * Open the URL, most likely in a browser. Maybe. + */ + MULTIMC_LOGIC_EXPORT bool openUrl(const QUrl &url); +}; diff --git a/logic/FileSystem.cpp b/logic/FileSystem.cpp index 006356b3..049f1e38 100644 --- a/logic/FileSystem.cpp +++ b/logic/FileSystem.cpp @@ -6,8 +6,8 @@ #include #include #include -#include #include +#include namespace FS { @@ -304,22 +304,6 @@ QString DirNameFromString(QString string, QString inDir) return dirName; } -void openDirInDefaultProgram(QString path, bool ensureExists) -{ - QDir parentPath; - QDir dir(path); - if (!dir.exists()) - { - parentPath.mkpath(dir.absolutePath()); - } - QDesktopServices::openUrl(QUrl::fromLocalFile(dir.absolutePath())); -} - -void openFileInDefaultProgram(QString filename) -{ - QDesktopServices::openUrl(QUrl::fromLocalFile(filename)); -} - // Does the directory path contain any '!'? If yes, return true, otherwise false. // (This is a problem for Java) bool checkProblemticPathJava(QDir folder) @@ -449,4 +433,4 @@ bool createShortCut(QString location, QString dest, QStringList args, QString na return false; #endif } -} \ No newline at end of file +} diff --git a/logic/FileSystem.h b/logic/FileSystem.h index 5e21375b..80637f90 100644 --- a/logic/FileSystem.h +++ b/logic/FileSystem.h @@ -110,12 +110,6 @@ MULTIMC_LOGIC_EXPORT QString RemoveInvalidFilenameChars(QString string, QChar re MULTIMC_LOGIC_EXPORT QString DirNameFromString(QString string, QString inDir = "."); -/// Opens the given file in the default application. -MULTIMC_LOGIC_EXPORT void openFileInDefaultProgram(QString filename); - -/// Opens the given directory in the default application. -MULTIMC_LOGIC_EXPORT void openDirInDefaultProgram(QString dirpath, bool ensureExists = false); - /// Checks if the a given Path contains "!" MULTIMC_LOGIC_EXPORT bool checkProblemticPathJava(QDir folder); diff --git a/logic/tools/MCEditTool.cpp b/logic/tools/MCEditTool.cpp index db45797f..f0f715c3 100644 --- a/logic/tools/MCEditTool.cpp +++ b/logic/tools/MCEditTool.cpp @@ -2,7 +2,6 @@ #include #include -#include #include // FIXME: mixing logic and UI!!!! #include @@ -11,6 +10,7 @@ #include "settings/SettingsObject.h" #include "BaseInstance.h" #include "minecraft/MinecraftInstance.h" +#include MCEditTool::MCEditTool(SettingsObjectPtr settings, InstancePtr instance, QObject *parent) : BaseDetachedTool(settings, instance, parent) @@ -84,7 +84,7 @@ void MCEditTool::runImpl() #endif if(program.size()) { - QProcess::startDetached(program, QStringList() << save, mceditPath); + DesktopServices::openFile(program, save, mceditPath); } #endif } -- cgit v1.2.3