Simplify Unix implementation of QProcess::start{Process|Detached}

Use QStandardPaths::findExecutable instead of duplicated
implementations.

Change-Id: Ia944f1d343d8c215fc2b6e78dae6b2bfffbba688
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Joerg Bornemann 2017-03-28 18:05:19 +02:00
parent 31e782cc96
commit 28666d167a
2 changed files with 28 additions and 65 deletions

View File

@ -353,7 +353,7 @@ public:
void start(QIODevice::OpenMode mode);
void startProcess();
#if defined(Q_OS_UNIX)
void execChild(const char *workingDirectory, char **path, char **argv, char **envp);
void execChild(const char *workingDirectory, char **argv, char **envp);
#endif
bool processStarted(QString *errorMessage = Q_NULLPTR);
void terminateProcess();

View File

@ -87,6 +87,7 @@ QT_END_NAMESPACE
#include "qprocess.h"
#include "qprocess_p.h"
#include "qstandardpaths.h"
#include "private/qcore_unix_p.h"
#ifdef Q_OS_MAC
@ -420,8 +421,16 @@ void QProcessPrivate::startProcess()
#endif
// Add the program name to the argument list.
char *dupProgramName = ::strdup(encodedProgramName.constData());
argv[0] = dupProgramName;
argv[0] = nullptr;
if (!program.contains(QLatin1Char('/'))) {
const QString &exeFilePath = QStandardPaths::findExecutable(program);
if (!exeFilePath.isEmpty()) {
const QByteArray &tmp = QFile::encodeName(exeFilePath);
argv[0] = ::strdup(tmp.constData());
}
}
if (!argv[0])
argv[0] = ::strdup(encodedProgramName.constData());
// Add every argument to the list
for (int i = 0; i < arguments.count(); ++i)
@ -443,29 +452,6 @@ void QProcessPrivate::startProcess()
workingDirPtr = encodedWorkingDirectory.constData();
}
// If the program does not specify a path, generate a list of possible
// locations for the binary using the PATH environment variable.
char **path = 0;
int pathc = 0;
if (!program.contains(QLatin1Char('/'))) {
const QString pathEnv = QString::fromLocal8Bit(qgetenv("PATH"));
if (!pathEnv.isEmpty()) {
QStringList pathEntries = pathEnv.split(QLatin1Char(':'), QString::SkipEmptyParts);
if (!pathEntries.isEmpty()) {
pathc = pathEntries.size();
path = new char *[pathc + 1];
path[pathc] = 0;
for (int k = 0; k < pathEntries.size(); ++k) {
QByteArray tmp = QFile::encodeName(pathEntries.at(k));
if (!tmp.endsWith('/')) tmp += '/';
tmp += encodedProgramName;
path[k] = ::strdup(tmp.constData());
}
}
}
}
// Start the process manager, and fork off the child process.
pid_t childPid;
forkfd = ::forkfd(FFD_CLOEXEC, &childPid);
@ -473,16 +459,12 @@ void QProcessPrivate::startProcess()
if (forkfd != FFD_CHILD_PROCESS) {
// Parent process.
// Clean up duplicated memory.
free(dupProgramName);
for (int i = 1; i <= arguments.count(); ++i)
for (int i = 0; i <= arguments.count(); ++i)
free(argv[i]);
for (int i = 0; i < envc; ++i)
free(envp[i]);
for (int i = 0; i < pathc; ++i)
free(path[i]);
delete [] argv;
delete [] envp;
delete [] path;
}
// On QNX, if spawnChild failed, childPid will be -1 but forkfd is still 0.
@ -503,7 +485,7 @@ void QProcessPrivate::startProcess()
// Start the child.
if (forkfd == FFD_CHILD_PROCESS) {
execChild(workingDirPtr, path, argv, envp);
execChild(workingDirPtr, argv, envp);
::_exit(-1);
}
@ -544,7 +526,7 @@ void QProcessPrivate::startProcess()
}
}
void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv, char **envp)
void QProcessPrivate::execChild(const char *workingDir, char **argv, char **envp)
{
::signal(SIGPIPE, SIG_DFL); // reset the signal that we ignored
@ -567,7 +549,7 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv
}
}
// make sure this fd is closed if execvp() succeeds
// make sure this fd is closed if execv() succeeds
qt_safe_close(childStartedPipe[0]);
// enter the working directory
@ -582,25 +564,13 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv
// execute the process
if (!envp) {
qt_safe_execvp(argv[0], argv);
callthatfailed = "execvp: ";
qt_safe_execv(argv[0], argv);
callthatfailed = "execv: ";
} else {
if (path) {
char **arg = path;
while (*arg) {
argv[0] = *arg;
#if defined (QPROCESS_DEBUG)
fprintf(stderr, "QProcessPrivate::execChild() searching / starting %s\n", argv[0]);
fprintf(stderr, "QProcessPrivate::execChild() starting %s\n", argv[0]);
#endif
qt_safe_execve(argv[0], argv, envp);
++arg;
}
} else {
#if defined (QPROCESS_DEBUG)
fprintf(stderr, "QProcessPrivate::execChild() starting %s\n", argv[0]);
#endif
qt_safe_execve(argv[0], argv, envp);
}
qt_safe_execve(argv[0], argv, envp);
callthatfailed = "execve: ";
}
@ -967,23 +937,16 @@ bool QProcessPrivate::startDetached(qint64 *pid)
argv[i + 1] = ::strdup(QFile::encodeName(arguments.at(i)).constData());
argv[arguments.size() + 1] = 0;
QByteArray tmp;
if (!program.contains(QLatin1Char('/'))) {
const QString path = QString::fromLocal8Bit(qgetenv("PATH"));
if (!path.isEmpty()) {
QStringList pathEntries = path.split(QLatin1Char(':'));
for (int k = 0; k < pathEntries.size(); ++k) {
QByteArray tmp = QFile::encodeName(pathEntries.at(k));
if (!tmp.endsWith('/')) tmp += '/';
tmp += QFile::encodeName(program);
argv[0] = tmp.data();
qt_safe_execv(argv[0], argv);
}
}
} else {
QByteArray tmp = QFile::encodeName(program);
argv[0] = tmp.data();
qt_safe_execv(argv[0], argv);
const QString &exeFilePath = QStandardPaths::findExecutable(program);
if (!exeFilePath.isEmpty())
tmp = QFile::encodeName(exeFilePath);
}
if (tmp.isEmpty())
tmp = QFile::encodeName(program);
argv[0] = tmp.data();
qt_safe_execv(argv[0], argv);
struct sigaction noaction;
memset(&noaction, 0, sizeof(noaction));