QProcess: report the syscall that failed in the Unix child process
Prefix the error string message with either "chdir" or the "execvXX"- family function that failed. In order to simplify the process, I also made it transmit local 8-bit data instead of UTF-16 (this also avoids memory allocation with QString). Since there are now two write(2) calls, it's possible for the parent process to be woken up and read(2) only the first. The parent process now needs to wait for EOF. Change-Id: Ib306f8f647014b399b87ffff13f1956199a5aee0 Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
This commit is contained in:
parent
16cd053331
commit
6d78b7a0c4
@ -1194,7 +1194,7 @@ bool QProcessPrivate::_q_startupNotification()
|
|||||||
}
|
}
|
||||||
|
|
||||||
q->setProcessState(QProcess::NotRunning);
|
q->setProcessState(QProcess::NotRunning);
|
||||||
setErrorAndEmit(QProcess::FailedToStart);
|
setErrorAndEmit(QProcess::FailedToStart, errorString); // the error string was already set
|
||||||
#ifdef Q_OS_UNIX
|
#ifdef Q_OS_UNIX
|
||||||
// make sure the process manager removes this entry
|
// make sure the process manager removes this entry
|
||||||
waitForDeadChild();
|
waitForDeadChild();
|
||||||
|
@ -672,6 +672,7 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv
|
|||||||
qt_safe_close(childStartedPipe[0]);
|
qt_safe_close(childStartedPipe[0]);
|
||||||
|
|
||||||
// enter the working directory
|
// enter the working directory
|
||||||
|
const char *callthatfailed = "chdir: ";
|
||||||
if (workingDir && QT_CHDIR(workingDir) == -1) {
|
if (workingDir && QT_CHDIR(workingDir) == -1) {
|
||||||
// failed, stop the process
|
// failed, stop the process
|
||||||
goto report_errno;
|
goto report_errno;
|
||||||
@ -683,6 +684,7 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv
|
|||||||
// execute the process
|
// execute the process
|
||||||
if (!envp) {
|
if (!envp) {
|
||||||
qt_safe_execvp(argv[0], argv);
|
qt_safe_execvp(argv[0], argv);
|
||||||
|
callthatfailed = "execvp: ";
|
||||||
} else {
|
} else {
|
||||||
if (path) {
|
if (path) {
|
||||||
char **arg = path;
|
char **arg = path;
|
||||||
@ -700,15 +702,19 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv
|
|||||||
#endif
|
#endif
|
||||||
qt_safe_execve(argv[0], argv, envp);
|
qt_safe_execve(argv[0], argv, envp);
|
||||||
}
|
}
|
||||||
|
callthatfailed = "execve: ";
|
||||||
}
|
}
|
||||||
|
|
||||||
// notify failure
|
// notify failure
|
||||||
|
// we're running in the child process, so we don't need to be thread-safe;
|
||||||
|
// we can use strerror
|
||||||
report_errno:
|
report_errno:
|
||||||
QString error = qt_error_string(errno);
|
const char *msg = strerror(errno);
|
||||||
#if defined (QPROCESS_DEBUG)
|
#if defined (QPROCESS_DEBUG)
|
||||||
fprintf(stderr, "QProcessPrivate::execChild() failed (%s), notifying parent process\n", qPrintable(error));
|
fprintf(stderr, "QProcessPrivate::execChild() failed (%s), notifying parent process\n", msg);
|
||||||
#endif
|
#endif
|
||||||
qt_safe_write(childStartedPipe[1], error.data(), error.length() * sizeof(QChar));
|
qt_safe_write(childStartedPipe[1], callthatfailed, strlen(callthatfailed));
|
||||||
|
qt_safe_write(childStartedPipe[1], msg, strlen(msg));
|
||||||
qt_safe_close(childStartedPipe[1]);
|
qt_safe_close(childStartedPipe[1]);
|
||||||
childStartedPipe[1] = -1;
|
childStartedPipe[1] = -1;
|
||||||
}
|
}
|
||||||
@ -716,8 +722,15 @@ report_errno:
|
|||||||
|
|
||||||
bool QProcessPrivate::processStarted()
|
bool QProcessPrivate::processStarted()
|
||||||
{
|
{
|
||||||
ushort buf[errorBufferMax];
|
char buf[errorBufferMax];
|
||||||
int i = qt_safe_read(childStartedPipe[0], &buf, sizeof buf);
|
int i = 0;
|
||||||
|
int ret;
|
||||||
|
do {
|
||||||
|
ret = qt_safe_read(childStartedPipe[0], buf + i, sizeof buf - i);
|
||||||
|
if (ret > 0)
|
||||||
|
i += ret;
|
||||||
|
} while (ret > 0 && i < int(sizeof buf));
|
||||||
|
|
||||||
if (startupSocketNotifier) {
|
if (startupSocketNotifier) {
|
||||||
startupSocketNotifier->setEnabled(false);
|
startupSocketNotifier->setEnabled(false);
|
||||||
startupSocketNotifier->deleteLater();
|
startupSocketNotifier->deleteLater();
|
||||||
@ -732,7 +745,7 @@ bool QProcessPrivate::processStarted()
|
|||||||
|
|
||||||
// did we read an error message?
|
// did we read an error message?
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
q_func()->setErrorString(QString((const QChar *)buf, i / sizeof(QChar)));
|
q_func()->setErrorString(QString::fromLocal8Bit(buf, i));
|
||||||
|
|
||||||
return i <= 0;
|
return i <= 0;
|
||||||
}
|
}
|
||||||
|
@ -2285,6 +2285,13 @@ void tst_QProcess::setNonExistentWorkingDirectory()
|
|||||||
#endif
|
#endif
|
||||||
QCOMPARE(int(process->error()), int(QProcess::FailedToStart));
|
QCOMPARE(int(process->error()), int(QProcess::FailedToStart));
|
||||||
|
|
||||||
|
#ifdef Q_OS_UNIX
|
||||||
|
# ifdef QPROCESS_USE_SPAWN
|
||||||
|
QEXPECT_FAIL("", "QProcess cannot detect failure to start when using posix_spawn()", Continue);
|
||||||
|
# endif
|
||||||
|
QVERIFY2(process->errorString().startsWith("chdir:"), process->errorString().toLocal8Bit());
|
||||||
|
#endif
|
||||||
|
|
||||||
delete process;
|
delete process;
|
||||||
process = 0;
|
process = 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user