1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42//#define QPROCESS_DEBUG
43#include "qdebug.h"
44
45#ifndef QT_NO_PROCESS
46
47#if defined QPROCESS_DEBUG
48#include "qstring.h"
49#include <ctype.h>
50
51/*
52 Returns a human readable representation of the first \a len
53 characters in \a data.
54*/
55QT_BEGIN_NAMESPACE
56static QByteArray qt_prettyDebug(const char *data, int len, int maxSize)
57{
58 if (!data) return "(null)";
59 QByteArray out;
60 for (int i = 0; i < len; ++i) {
61 char c = data[i];
62 if (isprint(c)) {
63 out += c;
64 } else switch (c) {
65 case '\n': out += "\\n"; break;
66 case '\r': out += "\\r"; break;
67 case '\t': out += "\\t"; break;
68 default:
69 QString tmp;
70 tmp.sprintf("\\%o", c);
71 out += tmp.toLatin1();
72 }
73 }
74
75 if (len < maxSize)
76 out += "...";
77
78 return out;
79}
80QT_END_NAMESPACE
81#endif
82
83#include "qplatformdefs.h"
84
85#include "qprocess.h"
86#include "qprocess_p.h"
87#include "private/qcore_unix_p.h"
88
89#ifdef Q_OS_MAC
90#include <private/qcore_mac_p.h>
91#endif
92
93#include <private/qcoreapplication_p.h>
94#include <private/qthread_p.h>
95#include <qfile.h>
96#include <qfileinfo.h>
97#include <qlist.h>
98#include <qhash.h>
99#include <qmutex.h>
100#include <qsemaphore.h>
101#include <qsocketnotifier.h>
102#include <qthread.h>
103#include <qelapsedtimer.h>
104
105#include <errno.h>
106#include <stdlib.h>
107#include <string.h>
108#ifdef Q_OS_QNX
109#include "qvarlengtharray.h"
110
111#include <spawn.h>
112#include <sys/neutrino.h>
113#endif
114
115
116QT_BEGIN_NAMESPACE
117
118// POSIX requires PIPE_BUF to be 512 or larger
119// so we will use 512
120static const int errorBufferMax = 512;
121
122#ifdef Q_OS_INTEGRITY
123static inline char *strdup(const char *data)
124{
125 return qstrdup(data);
126}
127#endif
128
129static int qt_qprocess_deadChild_pipe[2];
130static struct sigaction qt_sa_old_sigchld_handler;
131static void qt_sa_sigchld_sigaction(int signum, siginfo_t *info, void *context)
132{
133 // *Never* use the info or contect variables in this function
134 // (except for passing them to the next signal in the chain).
135 // We cannot be sure if another library or if the application
136 // installed a signal handler for SIGCHLD without SA_SIGINFO
137 // and fails to pass the arguments to us. If they do that,
138 // these arguments contain garbage and we'd most likely crash.
139
140 qt_safe_write(qt_qprocess_deadChild_pipe[1], "", 1);
141#if defined (QPROCESS_DEBUG)
142 fprintf(stderr, "*** SIGCHLD\n");
143#endif
144
145 // load as volatile
146 volatile struct sigaction *vsa = &qt_sa_old_sigchld_handler;
147
148 if (qt_sa_old_sigchld_handler.sa_flags & SA_SIGINFO) {
149 void (*oldAction)(int, siginfo_t *, void *) = vsa->sa_sigaction;
150
151 if (oldAction)
152 oldAction(signum, info, context);
153 } else {
154 void (*oldAction)(int) = vsa->sa_handler;
155
156 if (oldAction && oldAction != SIG_IGN)
157 oldAction(signum);
158 }
159}
160
161static inline void add_fd(int &nfds, int fd, fd_set *fdset)
162{
163 FD_SET(fd, fdset);
164 if ((fd) > nfds)
165 nfds = fd;
166}
167
168struct QProcessInfo {
169 QProcess *process;
170 int deathPipe;
171 int exitResult;
172 pid_t pid;
173 int serialNumber;
174};
175
176class QProcessManager : public QThread
177{
178 Q_OBJECT
179public:
180 QProcessManager();
181 ~QProcessManager();
182
183 void run();
184 void catchDeadChildren();
185 void add(pid_t pid, QProcess *process);
186 void remove(QProcess *process);
187 void lock();
188 void unlock();
189
190private:
191 QMutex mutex;
192 QHash<int, QProcessInfo *> children;
193};
194
195
196Q_GLOBAL_STATIC(QMutex, processManagerGlobalMutex)
197
198static QProcessManager *processManager() {
199 // The constructor of QProcessManager should be called only once
200 // so we cannot use Q_GLOBAL_STATIC directly for QProcessManager
201 QMutex *mutex = processManagerGlobalMutex();
202 QMutexLocker locker(mutex);
203 static QProcessManager processManager;
204 return &processManager;
205}
206
207QProcessManager::QProcessManager()
208{
209#if defined (QPROCESS_DEBUG)
210 qDebug() << "QProcessManager::QProcessManager()";
211#endif
212 // initialize the dead child pipe and make it non-blocking. in the
213 // extremely unlikely event that the pipe fills up, we do not under any
214 // circumstances want to block.
215 qt_safe_pipe(qt_qprocess_deadChild_pipe, O_NONBLOCK);
216
217 // set up the SIGCHLD handler, which writes a single byte to the dead
218 // child pipe every time a child dies.
219
220 struct sigaction action;
221 // use the old handler as template, i.e., preserve the signal mask
222 // otherwise the original signal handler might be interrupted although it
223 // was marked to never be interrupted
224 ::sigaction(SIGCHLD, NULL, &action);
225 action.sa_sigaction = qt_sa_sigchld_sigaction;
226 // set the SA_SIGINFO flag such that we can use the three argument handler
227 // function
228 action.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
229 ::sigaction(SIGCHLD, &action, &qt_sa_old_sigchld_handler);
230}
231
232QProcessManager::~QProcessManager()
233{
234 // notify the thread that we're shutting down.
235 qt_safe_write(qt_qprocess_deadChild_pipe[1], "@", 1);
236 qt_safe_close(qt_qprocess_deadChild_pipe[1]);
237 wait();
238
239 // on certain unixes, closing the reading end of the pipe will cause
240 // select in run() to block forever, rather than return with EBADF.
241 qt_safe_close(qt_qprocess_deadChild_pipe[0]);
242
243 qt_qprocess_deadChild_pipe[0] = -1;
244 qt_qprocess_deadChild_pipe[1] = -1;
245
246 qDeleteAll(children.values());
247 children.clear();
248
249 struct sigaction currentAction;
250 ::sigaction(SIGCHLD, 0, &currentAction);
251 if (currentAction.sa_sigaction == qt_sa_sigchld_sigaction) {
252 ::sigaction(SIGCHLD, &qt_sa_old_sigchld_handler, 0);
253 }
254}
255
256void QProcessManager::run()
257{
258 forever {
259 fd_set readset;
260 FD_ZERO(&readset);
261 FD_SET(qt_qprocess_deadChild_pipe[0], &readset);
262
263#if defined (QPROCESS_DEBUG)
264 qDebug() << "QProcessManager::run() waiting for children to die";
265#endif
266
267 // block forever, or until activity is detected on the dead child
268 // pipe. the only other peers are the SIGCHLD signal handler, and the
269 // QProcessManager destructor.
270 int nselect = select(qt_qprocess_deadChild_pipe[0] + 1, &readset, 0, 0, 0);
271 if (nselect < 0) {
272 if (errno == EINTR)
273 continue;
274 break;
275 }
276
277 // empty only one byte from the pipe, even though several SIGCHLD
278 // signals may have been delivered in the meantime, to avoid race
279 // conditions.
280 char c;
281 if (qt_safe_read(qt_qprocess_deadChild_pipe[0], &c, 1) < 0 || c == '@')
282 break;
283
284 // catch any and all children that we can.
285 catchDeadChildren();
286 }
287}
288
289void QProcessManager::catchDeadChildren()
290{
291 QMutexLocker locker(&mutex);
292
293 // try to catch all children whose pid we have registered, and whose
294 // deathPipe is still valid (i.e, we have not already notified it).
295 QHash<int, QProcessInfo *>::Iterator it = children.begin();
296 while (it != children.end()) {
297 // notify all children that they may have died. they need to run
298 // waitpid() in their own thread.
299 QProcessInfo *info = it.value();
300 qt_safe_write(info->deathPipe, "", 1);
301
302#if defined (QPROCESS_DEBUG)
303 qDebug() << "QProcessManager::run() sending death notice to" << info->process;
304#endif
305 ++it;
306 }
307}
308
309static QBasicAtomicInt idCounter = Q_BASIC_ATOMIC_INITIALIZER(1);
310
311void QProcessManager::add(pid_t pid, QProcess *process)
312{
313#if defined (QPROCESS_DEBUG)
314 qDebug() << "QProcessManager::add() adding pid" << pid << "process" << process;
315#endif
316
317 // insert a new info structure for this process
318 QProcessInfo *info = new QProcessInfo;
319 info->process = process;
320 info->deathPipe = process->d_func()->deathPipe[1];
321 info->exitResult = 0;
322 info->pid = pid;
323
324 int serial = idCounter.fetchAndAddRelaxed(1);
325 process->d_func()->serial = serial;
326 children.insert(serial, info);
327}
328
329void QProcessManager::remove(QProcess *process)
330{
331 QMutexLocker locker(&mutex);
332
333 int serial = process->d_func()->serial;
334 QProcessInfo *info = children.take(serial);
335#if defined (QPROCESS_DEBUG)
336 if (info)
337 qDebug() << "QProcessManager::remove() removing pid" << info->pid << "process" << info->process;
338#endif
339 delete info;
340}
341
342void QProcessManager::lock()
343{
344 mutex.lock();
345}
346
347void QProcessManager::unlock()
348{
349 mutex.unlock();
350}
351
352static int qt_create_pipe(int *pipe)
353{
354 if (pipe[0] != -1)
355 qt_safe_close(pipe[0]);
356 if (pipe[1] != -1)
357 qt_safe_close(pipe[1]);
358 int pipe_ret = qt_safe_pipe(pipe);
359 if (pipe_ret != 0) {
360 qWarning("QProcessPrivate::createPipe: Cannot create pipe %p: %s",
361 pipe, qPrintable(qt_error_string(errno)));
362 }
363 return pipe_ret;
364}
365
366void QProcessPrivate::destroyPipe(int *pipe)
367{
368 if (pipe[1] != -1) {
369 qt_safe_close(pipe[1]);
370 pipe[1] = -1;
371 }
372 if (pipe[0] != -1) {
373 qt_safe_close(pipe[0]);
374 pipe[0] = -1;
375 }
376}
377
378/*
379 Create the pipes to a QProcessPrivate::Channel.
380
381 This function must be called in order: stdin, stdout, stderr
382*/
383bool QProcessPrivate::createChannel(Channel &channel)
384{
385 Q_Q(QProcess);
386
387 if (&channel == &stderrChannel && processChannelMode == QProcess::MergedChannels) {
388 channel.pipe[0] = -1;
389 channel.pipe[1] = -1;
390 return true;
391 }
392
393 if (channel.type == Channel::Normal) {
394 // we're piping this channel to our own process
395 if (qt_create_pipe(channel.pipe) != 0)
396 return false;
397
398 // create the socket notifiers
399 if (threadData->eventDispatcher) {
400 if (&channel == &stdinChannel) {
401 channel.notifier = new QSocketNotifier(channel.pipe[1],
402 QSocketNotifier::Write, q);
403 channel.notifier->setEnabled(false);
404 QObject::connect(channel.notifier, SIGNAL(activated(int)),
405 q, SLOT(_q_canWrite()));
406 } else {
407 channel.notifier = new QSocketNotifier(channel.pipe[0],
408 QSocketNotifier::Read, q);
409 const char *receiver;
410 if (&channel == &stdoutChannel)
411 receiver = SLOT(_q_canReadStandardOutput());
412 else
413 receiver = SLOT(_q_canReadStandardError());
414 QObject::connect(channel.notifier, SIGNAL(activated(int)),
415 q, receiver);
416 }
417 }
418
419 return true;
420 } else if (channel.type == Channel::Redirect) {
421 // we're redirecting the channel to/from a file
422 QByteArray fname = QFile::encodeName(channel.file);
423
424 if (&channel == &stdinChannel) {
425 // try to open in read-only mode
426 channel.pipe[1] = -1;
427 if ( (channel.pipe[0] = qt_safe_open(fname, O_RDONLY)) != -1)
428 return true; // success
429
430 q->setErrorString(QProcess::tr("Could not open input redirection for reading"));
431 } else {
432 int mode = O_WRONLY | O_CREAT;
433 if (channel.append)
434 mode |= O_APPEND;
435 else
436 mode |= O_TRUNC;
437
438 channel.pipe[0] = -1;
439 if ( (channel.pipe[1] = qt_safe_open(fname, mode, 0666)) != -1)
440 return true; // success
441
442 q->setErrorString(QProcess::tr("Could not open output redirection for writing"));
443 }
444
445 // could not open file
446 processError = QProcess::FailedToStart;
447 emit q->error(processError);
448 cleanup();
449 return false;
450 } else {
451 Q_ASSERT_X(channel.process, "QProcess::start", "Internal error");
452
453 Channel *source;
454 Channel *sink;
455
456 if (channel.type == Channel::PipeSource) {
457 // we are the source
458 source = &channel;
459 sink = &channel.process->stdinChannel;
460
461 Q_ASSERT(source == &stdoutChannel);
462 Q_ASSERT(sink->process == this && sink->type == Channel::PipeSink);
463 } else {
464 // we are the sink;
465 source = &channel.process->stdoutChannel;
466 sink = &channel;
467
468 Q_ASSERT(sink == &stdinChannel);
469 Q_ASSERT(source->process == this && source->type == Channel::PipeSource);
470 }
471
472 if (source->pipe[1] != INVALID_Q_PIPE || sink->pipe[0] != INVALID_Q_PIPE) {
473 // already created, do nothing
474 return true;
475 } else {
476 Q_ASSERT(source->pipe[0] == INVALID_Q_PIPE && source->pipe[1] == INVALID_Q_PIPE);
477 Q_ASSERT(sink->pipe[0] == INVALID_Q_PIPE && sink->pipe[1] == INVALID_Q_PIPE);
478
479 Q_PIPE pipe[2] = { -1, -1 };
480 if (qt_create_pipe(pipe) != 0)
481 return false;
482 sink->pipe[0] = pipe[0];
483 source->pipe[1] = pipe[1];
484
485 return true;
486 }
487 }
488}
489
490QT_BEGIN_INCLUDE_NAMESPACE
491#if defined(Q_OS_MAC) && !defined(Q_OS_IOS)
492# include <crt_externs.h>
493# define environ (*_NSGetEnviron())
494#else
495 extern char **environ;
496#endif
497QT_END_INCLUDE_NAMESPACE
498
499QProcessEnvironment QProcessEnvironment::systemEnvironment()
500{
501 QProcessEnvironment env;
502#if !defined(Q_OS_IOS)
503 const char *entry;
504 for (int count = 0; (entry = environ[count]); ++count) {
505 const char *equal = strchr(entry, '=');
506 if (!equal)
507 continue;
508
509 QByteArray name(entry, equal - entry);
510 QByteArray value(equal + 1);
511 env.d->hash.insert(QProcessEnvironmentPrivate::Key(name),
512 QProcessEnvironmentPrivate::Value(value));
513 }
514#endif
515 return env;
516}
517
518static char **_q_dupEnvironment(const QProcessEnvironmentPrivate::Hash &environment, int *envc)
519{
520 *envc = 0;
521 if (environment.isEmpty())
522 return 0;
523
524 // if LD_LIBRARY_PATH exists in the current environment, but
525 // not in the environment list passed by the programmer, then
526 // copy it over.
527#if defined(Q_OS_MAC)
528 static const char libraryPath[] = "DYLD_LIBRARY_PATH";
529#else
530 static const char libraryPath[] = "LD_LIBRARY_PATH";
531#endif
532 const QByteArray envLibraryPath = qgetenv(libraryPath);
533 bool needToAddLibraryPath = !envLibraryPath.isEmpty() &&
534 !environment.contains(QProcessEnvironmentPrivate::Key(QByteArray(libraryPath)));
535
536 char **envp = new char *[environment.count() + 2];
537 envp[environment.count()] = 0;
538 envp[environment.count() + 1] = 0;
539
540 QProcessEnvironmentPrivate::Hash::ConstIterator it = environment.constBegin();
541 const QProcessEnvironmentPrivate::Hash::ConstIterator end = environment.constEnd();
542 for ( ; it != end; ++it) {
543 QByteArray key = it.key().key;
544 QByteArray value = it.value().bytes();
545 key.reserve(key.length() + 1 + value.length());
546 key.append('=');
547 key.append(value);
548
549 envp[(*envc)++] = ::strdup(key.constData());
550 }
551
552 if (needToAddLibraryPath)
553 envp[(*envc)++] = ::strdup(QByteArray(QByteArray(libraryPath) + '=' +
554 envLibraryPath).constData());
555 return envp;
556}
557
558#ifdef Q_OS_MAC
559Q_GLOBAL_STATIC(QMutex, cfbundleMutex);
560#endif
561
562void QProcessPrivate::startProcess()
563{
564 Q_Q(QProcess);
565
566#if defined (QPROCESS_DEBUG)
567 qDebug("QProcessPrivate::startProcess()");
568#endif
569
570 processManager()->start();
571
572 // Initialize pipes
573 if (!createChannel(stdinChannel) ||
574 !createChannel(stdoutChannel) ||
575 !createChannel(stderrChannel) ||
576 qt_create_pipe(childStartedPipe) != 0 ||
577 qt_create_pipe(deathPipe) != 0) {
578 processError = QProcess::FailedToStart;
579 q->setErrorString(qt_error_string(errno));
580 emit q->error(processError);
581 cleanup();
582 return;
583 }
584
585 if (threadData->eventDispatcher) {
586 startupSocketNotifier = new QSocketNotifier(childStartedPipe[0],
587 QSocketNotifier::Read, q);
588 QObject::connect(startupSocketNotifier, SIGNAL(activated(int)),
589 q, SLOT(_q_startupNotification()));
590 deathNotifier = new QSocketNotifier(deathPipe[0],
591 QSocketNotifier::Read, q);
592 QObject::connect(deathNotifier, SIGNAL(activated(int)),
593 q, SLOT(_q_processDied()));
594 }
595
596 // Start the process (platform dependent)
597 q->setProcessState(QProcess::Starting);
598
599 // Create argument list with right number of elements, and set the final
600 // one to 0.
601 char **argv = new char *[arguments.count() + 2];
602 argv[arguments.count() + 1] = 0;
603
604 // Encode the program name.
605 QByteArray encodedProgramName = QFile::encodeName(program);
606#ifdef Q_OS_MAC
607 // allow invoking of .app bundles on the Mac.
608 QFileInfo fileInfo(QString::fromUtf8(encodedProgramName.constData()));
609 if (encodedProgramName.endsWith(".app") && fileInfo.isDir()) {
610 QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0,
611 QCFString(fileInfo.absoluteFilePath()),
612 kCFURLPOSIXPathStyle, true);
613 {
614 // CFBundle is not reentrant, since CFBundleCreate might return a reference
615 // to a cached bundle object. Protect the bundle calls with a mutex lock.
616 QMutexLocker lock(cfbundleMutex());
617 QCFType<CFBundleRef> bundle = CFBundleCreate(0, url);
618 url = CFBundleCopyExecutableURL(bundle);
619 }
620 if (url) {
621 QCFString str = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
622 encodedProgramName += "/Contents/MacOS/" + static_cast<QString>(str).toUtf8();
623 }
624 }
625#endif
626
627 // Add the program name to the argument list.
628 char *dupProgramName = ::strdup(encodedProgramName.constData());
629 argv[0] = dupProgramName;
630
631 // Add every argument to the list
632 for (int i = 0; i < arguments.count(); ++i) {
633 QString arg = arguments.at(i);
634#ifdef Q_OS_MAC
635 // Mac OS X uses UTF8 for exec, regardless of the system locale.
636 argv[i + 1] = ::strdup(arg.toUtf8().constData());
637#else
638 argv[i + 1] = ::strdup(arg.toLocal8Bit().constData());
639#endif
640 }
641
642 // Duplicate the environment.
643 int envc = 0;
644 char **envp = 0;
645 if (environment.d.constData()) {
646 QProcessEnvironmentPrivate::MutexLocker locker(environment.d);
647 envp = _q_dupEnvironment(environment.d.constData()->hash, &envc);
648 }
649
650 // Encode the working directory if it's non-empty, otherwise just pass 0.
651 const char *workingDirPtr = 0;
652 QByteArray encodedWorkingDirectory;
653 if (!workingDirectory.isEmpty()) {
654 encodedWorkingDirectory = QFile::encodeName(workingDirectory);
655 workingDirPtr = encodedWorkingDirectory.constData();
656 }
657
658 // If the program does not specify a path, generate a list of possible
659 // locations for the binary using the PATH environment variable.
660 char **path = 0;
661 int pathc = 0;
662 if (!program.contains(QLatin1Char('/'))) {
663 const QString pathEnv = QString::fromLocal8Bit(::getenv("PATH"));
664 if (!pathEnv.isEmpty()) {
665 QStringList pathEntries = pathEnv.split(QLatin1Char(':'), QString::SkipEmptyParts);
666 if (!pathEntries.isEmpty()) {
667 pathc = pathEntries.size();
668 path = new char *[pathc + 1];
669 path[pathc] = 0;
670
671 for (int k = 0; k < pathEntries.size(); ++k) {
672 QByteArray tmp = QFile::encodeName(pathEntries.at(k));
673 if (!tmp.endsWith('/')) tmp += '/';
674 tmp += encodedProgramName;
675 path[k] = ::strdup(tmp.constData());
676 }
677 }
678 }
679 }
680
681 // Start the process manager, and fork off the child process.
682 processManager()->lock();
683#if defined(Q_OS_QNX)
684 pid_t childPid = spawnChild(workingDirPtr, argv, envp);
685#else
686 pid_t childPid = fork();
687 int lastForkErrno = errno;
688#endif
689 if (childPid != 0) {
690 // Clean up duplicated memory.
691 free(dupProgramName);
692 for (int i = 1; i <= arguments.count(); ++i)
693 free(argv[i]);
694 for (int i = 0; i < envc; ++i)
695 free(envp[i]);
696 for (int i = 0; i < pathc; ++i)
697 free(path[i]);
698 delete [] argv;
699 delete [] envp;
700 delete [] path;
701 }
702
703 // This is not a valid check under QNX, because the semantics are
704 // different. While under other platforms where fork() may succeed and exec() can still fail,
705 // causing the childPid to hold a valid value (and thus evaluating the
706 // following if to false), and then signaling the error via
707 // childStartedPipe, under QNX on the other hand, spawn() return value will be assigned
708 // to childPid (which will be -1 in case of failure). This will force
709 // QProcess to cleanup, instead of signaling the error via
710 // childStartedPipe. Since it will invalidade the pipes, functions like
711 // QProcess::waitForStarted() will fail, for childStartedPipe will be
712 // '-1' and mess with the select() calls.
713#if !defined(Q_OS_QNX)
714 if (childPid < 0) {
715 // Cleanup, report error and return
716#if defined (QPROCESS_DEBUG)
717 qDebug("fork() failed: %s", qPrintable(qt_error_string(lastForkErrno)));
718#endif
719 processManager()->unlock();
720 q->setProcessState(QProcess::NotRunning);
721 processError = QProcess::FailedToStart;
722 q->setErrorString(QProcess::tr("Resource error (fork failure): %1").arg(qt_error_string(lastForkErrno)));
723 emit q->error(processError);
724 cleanup();
725 return;
726 }
727
728 // Start the child.
729 if (childPid == 0) {
730 execChild(workingDirPtr, path, argv, envp);
731 ::_exit(-1);
732 }
733#endif
734
735 // Register the child. In the mean time, we can get a SIGCHLD, so we need
736 // to keep the lock held to avoid a race to catch the child.
737 processManager()->add(childPid, q);
738 pid = Q_PID(childPid);
739 processManager()->unlock();
740
741 // parent
742 // close the ends we don't use and make all pipes non-blocking
743 ::fcntl(deathPipe[0], F_SETFL, ::fcntl(deathPipe[0], F_GETFL) | O_NONBLOCK);
744 qt_safe_close(childStartedPipe[1]);
745 childStartedPipe[1] = -1;
746
747 if (stdinChannel.pipe[0] != -1) {
748 qt_safe_close(stdinChannel.pipe[0]);
749 stdinChannel.pipe[0] = -1;
750 }
751 if (stdinChannel.pipe[1] != -1)
752 ::fcntl(stdinChannel.pipe[1], F_SETFL, ::fcntl(stdinChannel.pipe[1], F_GETFL) | O_NONBLOCK);
753
754 if (stdoutChannel.pipe[1] != -1) {
755 qt_safe_close(stdoutChannel.pipe[1]);
756 stdoutChannel.pipe[1] = -1;
757 }
758 if (stdoutChannel.pipe[0] != -1)
759 ::fcntl(stdoutChannel.pipe[0], F_SETFL, ::fcntl(stdoutChannel.pipe[0], F_GETFL) | O_NONBLOCK);
760
761 if (stderrChannel.pipe[1] != -1) {
762 qt_safe_close(stderrChannel.pipe[1]);
763 stderrChannel.pipe[1] = -1;
764 }
765 if (stderrChannel.pipe[0] != -1)
766 ::fcntl(stderrChannel.pipe[0], F_SETFL, ::fcntl(stderrChannel.pipe[0], F_GETFL) | O_NONBLOCK);
767}
768
769#if !defined(Q_OS_QNX)
770void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv, char **envp)
771{
772 ::signal(SIGPIPE, SIG_DFL); // reset the signal that we ignored
773
774 Q_Q(QProcess);
775
776 // copy the stdin socket (without closing on exec)
777 qt_safe_dup2(stdinChannel.pipe[0], STDIN_FILENO, 0);
778
779 // copy the stdout and stderr if asked to
780 if (processChannelMode != QProcess::ForwardedChannels) {
781 qt_safe_dup2(stdoutChannel.pipe[1], STDOUT_FILENO, 0);
782
783 // merge stdout and stderr if asked to
784 if (processChannelMode == QProcess::MergedChannels) {
785 qt_safe_dup2(STDOUT_FILENO, STDERR_FILENO, 0);
786 } else {
787 qt_safe_dup2(stderrChannel.pipe[1], STDERR_FILENO, 0);
788 }
789 }
790
791 // make sure this fd is closed if execvp() succeeds
792 qt_safe_close(childStartedPipe[0]);
793
794 // enter the working directory
795 if (workingDir)
796 QT_CHDIR(workingDir);
797
798 // this is a virtual call, and it base behavior is to do nothing.
799 q->setupChildProcess();
800
801 // execute the process
802 if (!envp) {
803 qt_safe_execvp(argv[0], argv);
804 } else {
805 if (path) {
806 char **arg = path;
807 while (*arg) {
808 argv[0] = *arg;
809#if defined (QPROCESS_DEBUG)
810 fprintf(stderr, "QProcessPrivate::execChild() searching / starting %s\n", argv[0]);
811#endif
812 qt_safe_execve(argv[0], argv, envp);
813 ++arg;
814 }
815 } else {
816#if defined (QPROCESS_DEBUG)
817 fprintf(stderr, "QProcessPrivate::execChild() starting %s\n", argv[0]);
818#endif
819 qt_safe_execve(argv[0], argv, envp);
820 }
821 }
822
823 // notify failure
824 QString error = qt_error_string(errno);
825#if defined (QPROCESS_DEBUG)
826 fprintf(stderr, "QProcessPrivate::execChild() failed (%s), notifying parent process\n", qPrintable(error));
827#endif
828 qt_safe_write(childStartedPipe[1], error.data(), error.length() * sizeof(QChar));
829 qt_safe_close(childStartedPipe[1]);
830 childStartedPipe[1] = -1;
831}
832
833#endif //Q_OS_QNX
834
835bool QProcessPrivate::processStarted()
836{
837 ushort buf[errorBufferMax];
838 int i = qt_safe_read(childStartedPipe[0], &buf, sizeof buf);
839 if (startupSocketNotifier) {
840 startupSocketNotifier->setEnabled(false);
841 startupSocketNotifier->deleteLater();
842 startupSocketNotifier = 0;
843 }
844 qt_safe_close(childStartedPipe[0]);
845 childStartedPipe[0] = -1;
846
847#if defined (QPROCESS_DEBUG)
848 qDebug("QProcessPrivate::processStarted() == %s", i <= 0 ? "true" : "false");
849#endif
850
851 // did we read an error message?
852 if (i > 0)
853 q_func()->setErrorString(QString((const QChar *)buf, i / sizeof(QChar)));
854
855 return i <= 0;
856}
857
858#if defined(Q_OS_QNX)
859static pid_t doSpawn(int fd_count, int fd_map[], char **argv, char **envp,
860 const char *workingDir, bool spawn_detached)
861{
862 // A multi threaded QNX Process can't fork so we call spawn() instead.
863
864 struct inheritance inherit;
865 memset(&inherit, 0, sizeof(inherit));
866 inherit.flags |= SPAWN_SETSID;
867 inherit.flags |= SPAWN_CHECK_SCRIPT;
868 if (spawn_detached)
869 inherit.flags |= SPAWN_NOZOMBIE;
870 inherit.flags |= SPAWN_SETSIGDEF;
871 sigaddset(&inherit.sigdefault, SIGPIPE); // reset the signal that we ignored
872
873 // enter the working directory
874 const char *oldWorkingDir = 0;
875 char buff[PATH_MAX + 1];
876
877 if (workingDir) {
878 //we need to freeze everyone in order to avoid race conditions with //chdir().
879 if (ThreadCtl(_NTO_TCTL_THREADS_HOLD, 0) == -1)
880 qWarning("ThreadCtl(): cannot hold threads: %s", qPrintable(qt_error_string(errno)));
881
882 oldWorkingDir = QT_GETCWD(buff, PATH_MAX + 1);
883 QT_CHDIR(workingDir);
884 }
885
886 pid_t childPid;
887 EINTR_LOOP(childPid, ::spawn(argv[0], fd_count, fd_map, &inherit, argv, envp));
888 if (childPid == -1) {
889 inherit.flags |= SPAWN_SEARCH_PATH;
890 EINTR_LOOP(childPid, ::spawn(argv[0], fd_count, fd_map, &inherit, argv, envp));
891 }
892
893 if (oldWorkingDir) {
894 QT_CHDIR(oldWorkingDir);
895
896 if (ThreadCtl(_NTO_TCTL_THREADS_CONT, 0) == -1)
897 qFatal("ThreadCtl(): cannot resume threads: %s", qPrintable(qt_error_string(errno)));
898 }
899
900 return childPid;
901}
902
903pid_t QProcessPrivate::spawnChild(const char *workingDir, char **argv, char **envp)
904{
905 // we need to manually fill in fd_map
906 // to inherit the file descriptors from
907 // the parent
908 const int fd_count = sysconf(_SC_OPEN_MAX);
909 QVarLengthArray<int, 1024> fd_map(fd_count);
910
911 for (int i = 3; i < fd_count; ++i) {
912 // here we rely that fcntl returns -1 and
913 // sets errno to EBADF
914 const int flags = ::fcntl(i, F_GETFD);
915
916 fd_map[i] = ((flags >= 0) && !(flags & FD_CLOEXEC))
917 ? i : SPAWN_FDCLOSED;
918 }
919
920 switch (processChannelMode) {
921 case QProcess::ForwardedChannels:
922 fd_map[0] = stdinChannel.pipe[0];
923 fd_map[1] = QT_FILENO(stdout);
924 fd_map[2] = QT_FILENO(stderr);
925 break;
926 case QProcess::MergedChannels:
927 fd_map[0] = stdinChannel.pipe[0];
928 fd_map[1] = stdoutChannel.pipe[1];
929 fd_map[2] = stdoutChannel.pipe[1];
930 break;
931 case QProcess::SeparateChannels:
932 fd_map[0] = stdinChannel.pipe[0];
933 fd_map[1] = stdoutChannel.pipe[1];
934 fd_map[2] = stderrChannel.pipe[1];
935 break;
936 }
937
938 pid_t childPid = doSpawn(fd_count, fd_map.data(), argv, envp, workingDir, false);
939
940 if (childPid == -1) {
941 QString error = qt_error_string(errno);
942 qt_safe_write(childStartedPipe[1], error.data(), error.length() * sizeof(QChar));
943 qt_safe_close(childStartedPipe[1]);
944 childStartedPipe[1] = -1;
945 }
946
947 return childPid;
948}
949#endif // Q_OS_QNX
950
951qint64 QProcessPrivate::bytesAvailableFromStdout() const
952{
953 int nbytes = 0;
954 qint64 available = 0;
955 if (::ioctl(stdoutChannel.pipe[0], FIONREAD, (char *) &nbytes) >= 0)
956 available = (qint64) nbytes;
957#if defined (QPROCESS_DEBUG)
958 qDebug("QProcessPrivate::bytesAvailableFromStdout() == %lld", available);
959#endif
960 return available;
961}
962
963qint64 QProcessPrivate::bytesAvailableFromStderr() const
964{
965 int nbytes = 0;
966 qint64 available = 0;
967 if (::ioctl(stderrChannel.pipe[0], FIONREAD, (char *) &nbytes) >= 0)
968 available = (qint64) nbytes;
969#if defined (QPROCESS_DEBUG)
970 qDebug("QProcessPrivate::bytesAvailableFromStderr() == %lld", available);
971#endif
972 return available;
973}
974
975qint64 QProcessPrivate::readFromStdout(char *data, qint64 maxlen)
976{
977 qint64 bytesRead = qt_safe_read(stdoutChannel.pipe[0], data, maxlen);
978#if defined QPROCESS_DEBUG
979 qDebug("QProcessPrivate::readFromStdout(%p \"%s\", %lld) == %lld",
980 data, qt_prettyDebug(data, bytesRead, 16).constData(), maxlen, bytesRead);
981#endif
982 return bytesRead;
983}
984
985qint64 QProcessPrivate::readFromStderr(char *data, qint64 maxlen)
986{
987 qint64 bytesRead = qt_safe_read(stderrChannel.pipe[0], data, maxlen);
988#if defined QPROCESS_DEBUG
989 qDebug("QProcessPrivate::readFromStderr(%p \"%s\", %lld) == %lld",
990 data, qt_prettyDebug(data, bytesRead, 16).constData(), maxlen, bytesRead);
991#endif
992 return bytesRead;
993}
994
995qint64 QProcessPrivate::writeToStdin(const char *data, qint64 maxlen)
996{
997 qint64 written = qt_safe_write_nosignal(stdinChannel.pipe[1], data, maxlen);
998#if defined QPROCESS_DEBUG
999 qDebug("QProcessPrivate::writeToStdin(%p \"%s\", %lld) == %lld",
1000 data, qt_prettyDebug(data, maxlen, 16).constData(), maxlen, written);
1001 if (written == -1)
1002 qDebug("QProcessPrivate::writeToStdin(), failed to write (%s)", qPrintable(qt_error_string(errno)));
1003#endif
1004 // If the O_NONBLOCK flag is set and If some data can be written without blocking
1005 // the process, write() will transfer what it can and return the number of bytes written.
1006 // Otherwise, it will return -1 and set errno to EAGAIN
1007 if (written == -1 && errno == EAGAIN)
1008 written = 0;
1009 return written;
1010}
1011
1012void QProcessPrivate::terminateProcess()
1013{
1014#if defined (QPROCESS_DEBUG)
1015 qDebug("QProcessPrivate::killProcess()");
1016#endif
1017 if (pid)
1018 ::kill(pid_t(pid), SIGTERM);
1019}
1020
1021void QProcessPrivate::killProcess()
1022{
1023#if defined (QPROCESS_DEBUG)
1024 qDebug("QProcessPrivate::killProcess()");
1025#endif
1026 if (pid)
1027 ::kill(pid_t(pid), SIGKILL);
1028}
1029
1030static int select_msecs(int nfds, fd_set *fdread, fd_set *fdwrite, int timeout)
1031{
1032 if (timeout < 0)
1033 return qt_safe_select(nfds, fdread, fdwrite, 0, 0);
1034
1035 struct timeval tv;
1036 tv.tv_sec = timeout / 1000;
1037 tv.tv_usec = (timeout % 1000) * 1000;
1038 return qt_safe_select(nfds, fdread, fdwrite, 0, &tv);
1039}
1040
1041/*
1042 Returns the difference between msecs and elapsed. If msecs is -1,
1043 however, -1 is returned.
1044*/
1045static int qt_timeout_value(int msecs, int elapsed)
1046{
1047 if (msecs == -1)
1048 return -1;
1049
1050 int timeout = msecs - elapsed;
1051 return timeout < 0 ? 0 : timeout;
1052}
1053
1054bool QProcessPrivate::waitForStarted(int msecs)
1055{
1056 Q_Q(QProcess);
1057
1058#if defined (QPROCESS_DEBUG)
1059 qDebug("QProcessPrivate::waitForStarted(%d) waiting for child to start (fd = %d)", msecs,
1060 childStartedPipe[0]);
1061#endif
1062
1063 fd_set fds;
1064 FD_ZERO(&fds);
1065 FD_SET(childStartedPipe[0], &fds);
1066 if (select_msecs(childStartedPipe[0] + 1, &fds, 0, msecs) == 0) {
1067 processError = QProcess::Timedout;
1068 q->setErrorString(QProcess::tr("Process operation timed out"));
1069#if defined (QPROCESS_DEBUG)
1070 qDebug("QProcessPrivate::waitForStarted(%d) == false (timed out)", msecs);
1071#endif
1072 return false;
1073 }
1074
1075 bool startedEmitted = _q_startupNotification();
1076#if defined (QPROCESS_DEBUG)
1077 qDebug("QProcessPrivate::waitForStarted() == %s", startedEmitted ? "true" : "false");
1078#endif
1079 return startedEmitted;
1080}
1081
1082bool QProcessPrivate::waitForReadyRead(int msecs)
1083{
1084 Q_Q(QProcess);
1085#if defined (QPROCESS_DEBUG)
1086 qDebug("QProcessPrivate::waitForReadyRead(%d)", msecs);
1087#endif
1088
1089 QElapsedTimer stopWatch;
1090 stopWatch.start();
1091
1092 forever {
1093 fd_set fdread;
1094 fd_set fdwrite;
1095
1096 FD_ZERO(&fdread);
1097 FD_ZERO(&fdwrite);
1098
1099 int nfds = deathPipe[0];
1100 FD_SET(deathPipe[0], &fdread);
1101
1102 if (processState == QProcess::Starting)
1103 add_fd(nfds, childStartedPipe[0], &fdread);
1104
1105 if (stdoutChannel.pipe[0] != -1)
1106 add_fd(nfds, stdoutChannel.pipe[0], &fdread);
1107 if (stderrChannel.pipe[0] != -1)
1108 add_fd(nfds, stderrChannel.pipe[0], &fdread);
1109
1110 if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1)
1111 add_fd(nfds, stdinChannel.pipe[1], &fdwrite);
1112
1113 int timeout = qt_timeout_value(msecs, stopWatch.elapsed());
1114 int ret = select_msecs(nfds + 1, &fdread, &fdwrite, timeout);
1115 if (ret < 0) {
1116 break;
1117 }
1118 if (ret == 0) {
1119 processError = QProcess::Timedout;
1120 q->setErrorString(QProcess::tr("Process operation timed out"));
1121 return false;
1122 }
1123
1124 if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) {
1125 if (!_q_startupNotification())
1126 return false;
1127 }
1128
1129 bool readyReadEmitted = false;
1130 if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread)) {
1131 bool canRead = _q_canReadStandardOutput();
1132 if (processChannel == QProcess::StandardOutput && canRead)
1133 readyReadEmitted = true;
1134 }
1135 if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread)) {
1136 bool canRead = _q_canReadStandardError();
1137 if (processChannel == QProcess::StandardError && canRead)
1138 readyReadEmitted = true;
1139 }
1140 if (readyReadEmitted)
1141 return true;
1142
1143 if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
1144 _q_canWrite();
1145
1146 if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) {
1147 if (_q_processDied())
1148 return false;
1149 }
1150 }
1151 return false;
1152}
1153
1154bool QProcessPrivate::waitForBytesWritten(int msecs)
1155{
1156 Q_Q(QProcess);
1157#if defined (QPROCESS_DEBUG)
1158 qDebug("QProcessPrivate::waitForBytesWritten(%d)", msecs);
1159#endif
1160
1161 QElapsedTimer stopWatch;
1162 stopWatch.start();
1163
1164 while (!writeBuffer.isEmpty()) {
1165 fd_set fdread;
1166 fd_set fdwrite;
1167
1168 FD_ZERO(&fdread);
1169 FD_ZERO(&fdwrite);
1170
1171 int nfds = deathPipe[0];
1172 FD_SET(deathPipe[0], &fdread);
1173
1174 if (processState == QProcess::Starting)
1175 add_fd(nfds, childStartedPipe[0], &fdread);
1176
1177 if (stdoutChannel.pipe[0] != -1)
1178 add_fd(nfds, stdoutChannel.pipe[0], &fdread);
1179 if (stderrChannel.pipe[0] != -1)
1180 add_fd(nfds, stderrChannel.pipe[0], &fdread);
1181
1182
1183 if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1)
1184 add_fd(nfds, stdinChannel.pipe[1], &fdwrite);
1185
1186 int timeout = qt_timeout_value(msecs, stopWatch.elapsed());
1187 int ret = select_msecs(nfds + 1, &fdread, &fdwrite, timeout);
1188 if (ret < 0) {
1189 break;
1190 }
1191
1192 if (ret == 0) {
1193 processError = QProcess::Timedout;
1194 q->setErrorString(QProcess::tr("Process operation timed out"));
1195 return false;
1196 }
1197
1198 if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) {
1199 if (!_q_startupNotification())
1200 return false;
1201 }
1202
1203 if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
1204 return _q_canWrite();
1205
1206 if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread))
1207 _q_canReadStandardOutput();
1208
1209 if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread))
1210 _q_canReadStandardError();
1211
1212 if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) {
1213 if (_q_processDied())
1214 return false;
1215 }
1216 }
1217
1218 return false;
1219}
1220
1221bool QProcessPrivate::waitForFinished(int msecs)
1222{
1223 Q_Q(QProcess);
1224#if defined (QPROCESS_DEBUG)
1225 qDebug("QProcessPrivate::waitForFinished(%d)", msecs);
1226#endif
1227
1228 QElapsedTimer stopWatch;
1229 stopWatch.start();
1230
1231 forever {
1232 fd_set fdread;
1233 fd_set fdwrite;
1234 int nfds = -1;
1235
1236 FD_ZERO(&fdread);
1237 FD_ZERO(&fdwrite);
1238
1239 if (processState == QProcess::Starting)
1240 add_fd(nfds, childStartedPipe[0], &fdread);
1241
1242 if (stdoutChannel.pipe[0] != -1)
1243 add_fd(nfds, stdoutChannel.pipe[0], &fdread);
1244 if (stderrChannel.pipe[0] != -1)
1245 add_fd(nfds, stderrChannel.pipe[0], &fdread);
1246
1247 if (processState == QProcess::Running)
1248 add_fd(nfds, deathPipe[0], &fdread);
1249
1250 if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1)
1251 add_fd(nfds, stdinChannel.pipe[1], &fdwrite);
1252
1253 int timeout = qt_timeout_value(msecs, stopWatch.elapsed());
1254 int ret = select_msecs(nfds + 1, &fdread, &fdwrite, timeout);
1255 if (ret < 0) {
1256 break;
1257 }
1258 if (ret == 0) {
1259 processError = QProcess::Timedout;
1260 q->setErrorString(QProcess::tr("Process operation timed out"));
1261 return false;
1262 }
1263
1264 if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) {
1265 if (!_q_startupNotification())
1266 return false;
1267 }
1268 if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
1269 _q_canWrite();
1270
1271 if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread))
1272 _q_canReadStandardOutput();
1273
1274 if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread))
1275 _q_canReadStandardError();
1276
1277 if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) {
1278 if (_q_processDied())
1279 return true;
1280 }
1281 }
1282 return false;
1283}
1284
1285bool QProcessPrivate::waitForWrite(int msecs)
1286{
1287 fd_set fdwrite;
1288 FD_ZERO(&fdwrite);
1289 FD_SET(stdinChannel.pipe[1], &fdwrite);
1290 return select_msecs(stdinChannel.pipe[1] + 1, 0, &fdwrite, msecs < 0 ? 0 : msecs) == 1;
1291}
1292
1293void QProcessPrivate::findExitCode()
1294{
1295 Q_Q(QProcess);
1296 processManager()->remove(q);
1297}
1298
1299bool QProcessPrivate::waitForDeadChild()
1300{
1301 Q_Q(QProcess);
1302
1303 // read a byte from the death pipe
1304 char c;
1305 qt_safe_read(deathPipe[0], &c, 1);
1306
1307 // check if our process is dead
1308 int exitStatus;
1309 if (qt_safe_waitpid(pid_t(pid), &exitStatus, WNOHANG) > 0) {
1310 processManager()->remove(q);
1311 crashed = !WIFEXITED(exitStatus);
1312 exitCode = WEXITSTATUS(exitStatus);
1313#if defined QPROCESS_DEBUG
1314 qDebug() << "QProcessPrivate::waitForDeadChild() dead with exitCode"
1315 << exitCode << ", crashed?" << crashed;
1316#endif
1317 return true;
1318 }
1319#if defined QPROCESS_DEBUG
1320 qDebug() << "QProcessPrivate::waitForDeadChild() not dead!";
1321#endif
1322 return false;
1323}
1324
1325void QProcessPrivate::_q_notified()
1326{
1327}
1328
1329#if defined(Q_OS_QNX)
1330bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid)
1331{
1332 const int fd_count = 3;
1333 int fd_map[fd_count] = { QT_FILENO(stdin), QT_FILENO(stdout), QT_FILENO(stderr) };
1334
1335 QList<QByteArray> enc_args;
1336 enc_args.append(QFile::encodeName(program));
1337 for (int i = 0; i < arguments.size(); ++i)
1338 enc_args.append(arguments.at(i).toLocal8Bit());
1339
1340 const int argc = enc_args.size();
1341 QScopedArrayPointer<char*> raw_argv(new char*[argc + 1]);
1342 for (int i = 0; i < argc; ++i)
1343 raw_argv[i] = const_cast<char *>(enc_args.at(i).data());
1344 raw_argv[argc] = 0;
1345
1346 char **envp = 0; // inherit environment
1347
1348 // Encode the working directory if it's non-empty, otherwise just pass 0.
1349 const char *workingDirPtr = 0;
1350 QByteArray encodedWorkingDirectory;
1351 if (!workingDirectory.isEmpty()) {
1352 encodedWorkingDirectory = QFile::encodeName(workingDirectory);
1353 workingDirPtr = encodedWorkingDirectory.constData();
1354 }
1355
1356 pid_t childPid = doSpawn(fd_count, fd_map, raw_argv.data(), envp, workingDirPtr, true);
1357 if (pid && childPid != -1)
1358 *pid = childPid;
1359
1360 return childPid != -1;
1361}
1362
1363#else
1364
1365bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid)
1366{
1367 processManager()->start();
1368
1369 QByteArray encodedWorkingDirectory = QFile::encodeName(workingDirectory);
1370
1371 // To catch the startup of the child
1372 int startedPipe[2];
1373 if (qt_safe_pipe(startedPipe) != 0)
1374 return false;
1375 // To communicate the pid of the child
1376 int pidPipe[2];
1377 if (qt_safe_pipe(pidPipe) != 0) {
1378 qt_safe_close(startedPipe[0]);
1379 qt_safe_close(startedPipe[1]);
1380 return false;
1381 }
1382
1383 pid_t childPid = fork();
1384 if (childPid == 0) {
1385 struct sigaction noaction;
1386 memset(&noaction, 0, sizeof(noaction));
1387 noaction.sa_handler = SIG_IGN;
1388 ::sigaction(SIGPIPE, &noaction, 0);
1389
1390 ::setsid();
1391
1392 qt_safe_close(startedPipe[0]);
1393 qt_safe_close(pidPipe[0]);
1394
1395 pid_t doubleForkPid = fork();
1396 if (doubleForkPid == 0) {
1397 qt_safe_close(pidPipe[1]);
1398
1399 if (!encodedWorkingDirectory.isEmpty())
1400 QT_CHDIR(encodedWorkingDirectory.constData());
1401
1402 char **argv = new char *[arguments.size() + 2];
1403 for (int i = 0; i < arguments.size(); ++i) {
1404#ifdef Q_OS_MAC
1405 argv[i + 1] = ::strdup(arguments.at(i).toUtf8().constData());
1406#else
1407 argv[i + 1] = ::strdup(arguments.at(i).toLocal8Bit().constData());
1408#endif
1409 }
1410 argv[arguments.size() + 1] = 0;
1411
1412 if (!program.contains(QLatin1Char('/'))) {
1413 const QString path = QString::fromLocal8Bit(::getenv("PATH"));
1414 if (!path.isEmpty()) {
1415 QStringList pathEntries = path.split(QLatin1Char(':'));
1416 for (int k = 0; k < pathEntries.size(); ++k) {
1417 QByteArray tmp = QFile::encodeName(pathEntries.at(k));
1418 if (!tmp.endsWith('/')) tmp += '/';
1419 tmp += QFile::encodeName(program);
1420 argv[0] = tmp.data();
1421 qt_safe_execv(argv[0], argv);
1422 }
1423 }
1424 } else {
1425 QByteArray tmp = QFile::encodeName(program);
1426 argv[0] = tmp.data();
1427 qt_safe_execv(argv[0], argv);
1428 }
1429
1430 struct sigaction noaction;
1431 memset(&noaction, 0, sizeof(noaction));
1432 noaction.sa_handler = SIG_IGN;
1433 ::sigaction(SIGPIPE, &noaction, 0);
1434
1435 // '\1' means execv failed
1436 char c = '\1';
1437 qt_safe_write(startedPipe[1], &c, 1);
1438 qt_safe_close(startedPipe[1]);
1439 ::_exit(1);
1440 } else if (doubleForkPid == -1) {
1441 struct sigaction noaction;
1442 memset(&noaction, 0, sizeof(noaction));
1443 noaction.sa_handler = SIG_IGN;
1444 ::sigaction(SIGPIPE, &noaction, 0);
1445
1446 // '\2' means internal error
1447 char c = '\2';
1448 qt_safe_write(startedPipe[1], &c, 1);
1449 }
1450
1451 qt_safe_close(startedPipe[1]);
1452 qt_safe_write(pidPipe[1], (const char *)&doubleForkPid, sizeof(pid_t));
1453 QT_CHDIR("/");
1454 ::_exit(1);
1455 }
1456
1457 qt_safe_close(startedPipe[1]);
1458 qt_safe_close(pidPipe[1]);
1459
1460 if (childPid == -1) {
1461 qt_safe_close(startedPipe[0]);
1462 qt_safe_close(pidPipe[0]);
1463 return false;
1464 }
1465
1466 char reply = '\0';
1467 int startResult = qt_safe_read(startedPipe[0], &reply, 1);
1468 int result;
1469 qt_safe_close(startedPipe[0]);
1470 qt_safe_waitpid(childPid, &result, 0);
1471 bool success = (startResult != -1 && reply == '\0');
1472 if (success && pid) {
1473 pid_t actualPid = 0;
1474 if (qt_safe_read(pidPipe[0], (char *)&actualPid, sizeof(pid_t)) == sizeof(pid_t)) {
1475 *pid = actualPid;
1476 } else {
1477 *pid = 0;
1478 }
1479 }
1480 qt_safe_close(pidPipe[0]);
1481 return success;
1482}
1483#endif // Q_OS_QNX
1484
1485void QProcessPrivate::initializeProcessManager()
1486{
1487 (void) processManager();
1488}
1489
1490QT_END_NAMESPACE
1491
1492#include "qprocess_unix.moc"
1493
1494#endif // QT_NO_PROCESS
1495