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