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
This commit is contained in:
Petr Mrázek
2016-01-05 07:32:52 +01:00
parent d1e344f28f
commit 4d0caf6254
19 changed files with 235 additions and 72 deletions

View File

@ -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

149
logic/DesktopServices.cpp Normal file
View File

@ -0,0 +1,149 @@
#include "DesktopServices.h"
#include <QDir>
#include <QDesktopServices>
#include <QProcess>
#include <QDebug>
/**
* 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 <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
template <typename T>
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
}
}

37
logic/DesktopServices.h Normal file
View File

@ -0,0 +1,37 @@
#pragma once
#include <QUrl>
#include <QString>
#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);
};

View File

@ -6,8 +6,8 @@
#include <QSaveFile>
#include <QFileInfo>
#include <QDebug>
#include <QDesktopServices>
#include <QUrl>
#include <QStandardPaths>
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
}
}
}

View File

@ -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);

View File

@ -2,7 +2,6 @@
#include <QDir>
#include <QProcess>
#include <QDesktopServices>
#include <QUrl>
// FIXME: mixing logic and UI!!!!
#include <QInputDialog>
@ -11,6 +10,7 @@
#include "settings/SettingsObject.h"
#include "BaseInstance.h"
#include "minecraft/MinecraftInstance.h"
#include <DesktopServices.h>
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
}