Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qprocess_unix.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// Copyright (C) 2022 Intel Corporation.
3// Copyright (C) 2021 Alex Trotsenko.
4// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
5// Qt-Security score:critical reason:execute-external-code
6
7//#define QPROCESS_DEBUG
8#include "qdebug.h"
9#include <private/qdebug_p.h>
10#include "qplatformdefs.h"
11
12#include "qprocess.h"
13#include "qprocess_p.h"
14#include "qstandardpaths.h"
15#include "private/qcore_unix_p.h"
16#include "private/qlocking_p.h"
17
18#ifdef Q_OS_DARWIN
19#include <private/qcore_mac_p.h>
20#endif
21
22#include <private/qcoreapplication_p.h>
23#include <private/qthread_p.h>
24#include <qfile.h>
25#include <qfileinfo.h>
26#include <qdir.h>
27#include <qlist.h>
28#include <qmutex.h>
29#include <qsocketnotifier.h>
30#include <qthread.h>
31
32#ifdef Q_OS_QNX
33# include <sys/neutrino.h>
34#endif
35
36#include <errno.h>
37#include <limits.h>
38#include <stdlib.h>
39#include <string.h>
40#include <sys/resource.h>
41#include <termios.h>
42#include <unistd.h>
43
44#if __has_include(<paths.h>)
45# include <paths.h>
46#endif
47
48#if QT_CONFIG(process)
49#include <forkfd.h>
50#endif
51
52#ifndef O_PATH
53# define O_PATH 0
54#endif
55#ifndef _PATH_DEV
56# define _PATH_DEV "/dev/"
57#endif
58#ifndef _PATH_TTY
59# define _PATH_TTY _PATH_DEV "tty"
60#endif
61
62#ifdef Q_OS_FREEBSD
63__attribute__((weak))
64#endif
65extern char **environ;
66
67QT_BEGIN_NAMESPACE
68
69using namespace Qt::StringLiterals;
70
71#if !defined(Q_OS_DARWIN)
72
73QProcessEnvironment QProcessEnvironment::systemEnvironment()
74{
75 QProcessEnvironment env;
76 const char *entry;
77 for (int count = 0; (entry = environ[count]); ++count) {
78 const char *equal = strchr(entry, '=');
79 if (!equal)
80 continue;
81
82 QByteArray name(entry, equal - entry);
83 QByteArray value(equal + 1);
84 env.d->vars.insert(QProcessEnvironmentPrivate::Key(name),
85 QProcessEnvironmentPrivate::Value(value));
86 }
87 return env;
88}
89
90#endif // !defined(Q_OS_DARWIN)
91
92#if QT_CONFIG(process)
93
94namespace QtVforkSafe {
95// Certain libc functions we need to call in the child process scenario aren't
96// safe under vfork() because they do more than just place the system call to
97// the kernel and set errno on return. For those, we'll create a function
98// pointer like:
99// static constexpr auto foobar = __libc_foobar;
100// while for all other OSes, it'll be
101// using ::foobar;
102// allowing the code for the child side of the vfork to simply use
103// QtVforkSafe::foobar(args);
104//
105// Currently known issues are:
106//
107// - FreeBSD's libthr sigaction() wrapper locks a rwlock
108// https://github.com/freebsd/freebsd-src/blob/8dad5ece49479ba6cdcd5bb4c2799bbd61add3e6/lib/libthr/thread/thr_sig.c#L575-L641
109// - MUSL's sigaction() locks a mutex if the signal is SIGABR
110// https://github.com/bminor/musl/blob/718f363bc2067b6487900eddc9180c84e7739f80/src/signal/sigaction.c#L63-L85
111//
112// All other functions called in the child side are vfork-safe, provided that
113// PThread cancellation is disabled and Unix signals are blocked.
114#if defined(__MUSL__)
115# define LIBC_PREFIX __libc_
116#elif defined(Q_OS_FREEBSD)
117// will cause QtCore to link to ELF version "FBSDprivate_1.0"
118# define LIBC_PREFIX _
119#endif
120
121#ifdef LIBC_PREFIX
122# define CONCAT(x, y) CONCAT2(x, y)
123# define CONCAT2(x, y) x ## y
124# define DECLARE_FUNCTIONS(NAME)
125 extern decltype(::NAME) CONCAT(LIBC_PREFIX, NAME);
126 static constexpr auto NAME = std::addressof(CONCAT(LIBC_PREFIX, NAME));
127#else // LIBC_PREFIX
128# define DECLARE_FUNCTIONS(NAME) using ::NAME;
129#endif // LIBC_PREFIX
130
131extern "C" {
132DECLARE_FUNCTIONS(sigaction)
133}
134
135#undef LIBC_PREFIX
136#undef DECLARE_FUNCTIONS
137
138// similar to qt_ignore_sigpipe() in qcore_unix_p.h, but vfork-safe
139static void change_sigpipe(decltype(SIG_DFL) new_handler)
140{
141 struct sigaction sa;
142 memset(&sa, 0, sizeof(sa));
143 sa.sa_handler = new_handler;
144 sigaction(SIGPIPE, &sa, nullptr);
145}
146} // namespace QtVforkSafe
147
148static int opendirfd(QByteArray encodedName)
149{
150 // We append "/." to the name to ensure that the directory is actually
151 // traversable (i.e., has the +x bit set). This avoids later problems
152 // with fchdir().
153 if (encodedName != "/" && !encodedName.endsWith("/."))
154 encodedName += "/.";
155 return qt_safe_open(encodedName, QT_OPEN_RDONLY | O_DIRECTORY | O_PATH);
156}
157
158namespace {
159struct AutoPipe
160{
161 int pipe[2] = { -1, -1 };
162 AutoPipe(int flags = 0)
163 {
164 qt_safe_pipe(pipe, flags);
165 }
166 ~AutoPipe()
167 {
168 for (int fd : pipe) {
169 if (fd >= 0)
170 qt_safe_close(fd);
171 }
172 }
173
174 explicit operator bool() const { return pipe[0] >= 0; }
175 int &operator[](int idx) { return pipe[idx]; }
176 int operator[](int idx) const { return pipe[idx]; }
177};
178
179struct ChildError
180{
181 int code;
182 char function[_POSIX_PIPE_BUF - sizeof(code)];
183};
184static_assert(std::is_trivially_copy_constructible_v<ChildError>);
185#ifdef PIPE_BUF
186static_assert(PIPE_BUF >= sizeof(ChildError)); // PIPE_BUF may be bigger
187#endif
188
189// we need an errno value to use to indicate the child process modifier threw,
190// something the regular operations shouldn't set.
191static constexpr int FakeErrnoForThrow = std::numeric_limits<int>::max();
192
193static QString errorMessageForSyscall(QUtf8StringView fnName, int errnoCode = -1)
194{
195 QString msg = qt_error_string(errnoCode);
196 return QProcess::tr("Child process set up failed: %1: %2").arg(fnName, std::move(msg));
197}
198
199static QString startFailureErrorMessage(ChildError &err, [[maybe_unused]] ssize_t bytesRead)
200{
201 // ChildError is less than the POSIX pipe buffer atomic size, so the read
202 // must not have been truncated
203 Q_ASSERT(bytesRead == sizeof(err));
204
205 qsizetype len = qstrnlen(err.function, sizeof(err.function));
206 const QUtf8StringView complement(err.function, len);
207 if (err.code == FakeErrnoForThrow)
208 return QProcess::tr("Child process modifier threw an exception: %1")
209 .arg(complement);
210 if (err.code == 0)
211 return QProcess::tr("Child process modifier reported error: %1")
212 .arg(complement);
213 if (err.code < 0)
214 return QProcess::tr("Child process modifier reported error: %1: %2")
215 .arg(complement, qt_error_string(-err.code));
216 return errorMessageForSyscall(complement, err.code);
217}
218
219struct QProcessPoller
220{
221 QProcessPoller(const QProcessPrivate &proc);
222
223 int poll(const QDeadlineTimer &deadline);
224
225 pollfd &stdinPipe() { return pfds[0]; }
226 pollfd &stdoutPipe() { return pfds[1]; }
227 pollfd &stderrPipe() { return pfds[2]; }
228 pollfd &forkfd() { return pfds[3]; }
229
230 enum { n_pfds = 4 };
231 pollfd pfds[n_pfds];
232};
233
234QProcessPoller::QProcessPoller(const QProcessPrivate &proc)
235{
236 for (int i = 0; i < n_pfds; i++)
237 pfds[i] = qt_make_pollfd(-1, POLLIN);
238
239 stdoutPipe().fd = proc.stdoutChannel.pipe[0];
240 stderrPipe().fd = proc.stderrChannel.pipe[0];
241
242 if (!proc.writeBuffer.isEmpty()) {
243 stdinPipe().fd = proc.stdinChannel.pipe[1];
244 stdinPipe().events = POLLOUT;
245 }
246
247 forkfd().fd = proc.forkfd;
248}
249
250int QProcessPoller::poll(const QDeadlineTimer &deadline)
251{
252 return qt_safe_poll(pfds, n_pfds, deadline);
253}
254
255struct QChildProcess
256{
257 // Used for argv and envp arguments to execve()
258 struct CharPointerList
259 {
260 std::unique_ptr<char *[]> pointers;
261
262 CharPointerList(const QString &argv0, const QStringList &args);
263 explicit CharPointerList(const QProcessEnvironmentPrivate *env);
264 /*implicit*/ operator char **() const { return pointers.get(); }
265
266 private:
267 QByteArray data;
268 void updatePointers(qsizetype count);
269 };
270
271 const QProcessPrivate *d;
272 CharPointerList argv;
273 CharPointerList envp;
274 sigset_t oldsigset;
275 int workingDirectory = -2;
276 bool isUsingVfork = usingVfork();
277
278 bool ok() const
279 {
280 return workingDirectory != -1;
281 }
282
283 QChildProcess(QProcessPrivate *d)
284 : d(d), argv(resolveExecutable(d->program), d->arguments),
285 envp(d->environmentPrivate())
286 {
287 // Open the working directory first, because this operation can fail.
288 // That way, if it does, we don't have anything to clean up.
289 if (!d->workingDirectory.isEmpty()) {
290 workingDirectory = opendirfd(QFile::encodeName(d->workingDirectory));
291 if (workingDirectory < 0) {
292 d->setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall("chdir"));
293 d->cleanup();
294
295 // make sure our destructor does nothing
296 isUsingVfork = false;
297 return;
298 }
299 }
300
301 // Block Unix signals, to ensure the user's handlers aren't run in the
302 // child side and do something weird, especially if the handler and the
303 // user of QProcess are completely different codebases.
304 maybeBlockSignals();
305
306 // Disable PThread cancellation until the child has successfully been
307 // executed. We make a number of POSIX calls in the child that are thread
308 // cancellation points and could cause an unexpected stack unwind. That
309 // would be bad enough with regular fork(), but it's likely fatal with
310 // vfork().
311 disableThreadCancellations();
312 }
313 ~QChildProcess() noexcept(false)
314 {
315 cleanup();
316 }
317
318 void cleanup() noexcept(false)
319 {
320 if (workingDirectory >= 0)
321 close(workingDirectory);
322 workingDirectory = -1;
323
324 restoreSignalMask();
325 restoreThreadCancellations();
326 }
327
328 void maybeBlockSignals() noexcept
329 {
330 // We only block Unix signals if we're using vfork(), to avoid a
331 // changing behavior to the user's modifier and because in some OSes
332 // this action would block crashing signals too.
333 if (isUsingVfork) {
334 sigset_t emptyset;
335 sigfillset(&emptyset);
336 pthread_sigmask(SIG_SETMASK, &emptyset, &oldsigset);
337 }
338 }
339
340 void restoreSignalMask() const noexcept
341 {
342 // this function may be called more than once
343 if (isUsingVfork)
344 pthread_sigmask(SIG_SETMASK, &oldsigset, nullptr);
345 }
346
347 bool usingVfork() const noexcept;
348
349 template <typename Lambda> int doFork(Lambda &&childLambda)
350 {
351 pid_t pid;
352 if (isUsingVfork) {
353 QT_IGNORE_DEPRECATIONS(pid = vfork();)
354 } else {
355 pid = fork();
356 }
357 if (pid == 0)
358 _exit(childLambda());
359 return pid;
360 }
361
362 int startChild(pid_t *pid)
363 {
364 int ffdflags = FFD_CLOEXEC | (isUsingVfork ? 0 : FFD_USE_FORK);
365 return ::vforkfd(ffdflags, pid, &QChildProcess::startProcess, this);
366 }
367
368private:
369 Q_NORETURN void startProcess() const noexcept;
370 static int startProcess(void *self) noexcept
371 {
372 static_cast<QChildProcess *>(self)->startProcess();
373 Q_UNREACHABLE_RETURN(-1);
374 }
375
376#if defined(PTHREAD_CANCEL_DISABLE)
377 int oldstate = PTHREAD_CANCEL_DISABLE;
378 void disableThreadCancellations() noexcept
379 {
380 // the following is *not* noexcept, but it won't throw while disabling
381 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
382 }
383 void restoreThreadCancellations() noexcept(false)
384 {
385 // ensure we don't call pthread_setcancelstate() again
386 int oldoldstate = std::exchange(oldstate, PTHREAD_CANCEL_DISABLE);
387 if (oldoldstate != PTHREAD_CANCEL_DISABLE) {
388 // this doesn't touch errno
389 pthread_setcancelstate(oldoldstate, nullptr);
390 }
391 }
392#else
393 void disableThreadCancellations() noexcept {}
394 void restoreThreadCancellations() {}
395#endif
396
397 static QString resolveExecutable(const QString &program);
398};
399
400QChildProcess::CharPointerList::CharPointerList(const QString &program, const QStringList &args)
401{
402 qsizetype count = 1 + args.size();
403 pointers.reset(new char *[count + 1]);
404 pointers[count] = nullptr;
405
406 // we abuse the pointer array to store offsets first (QByteArray will
407 // reallocate, after all)
408 pointers[0] = reinterpret_cast<char *>(0);
409 data = QFile::encodeName(program);
410 data += '\0';
411
412 const auto end = args.end();
413 auto it = args.begin();
414 for (qsizetype i = 1; it != end; ++it, ++i) {
415 pointers[i] = reinterpret_cast<char *>(data.size());
416 data += QFile::encodeName(*it);
417 data += '\0';
418 }
419
420 updatePointers(count);
421}
422
423QChildProcess::CharPointerList::CharPointerList(const QProcessEnvironmentPrivate *environment)
424{
425 if (!environment)
426 return;
427
428 QProcessEnvironmentPrivate::MutexLocker locker(environment);
429
430 const QProcessEnvironmentPrivate::Map &env = environment->vars;
431 qsizetype count = env.size();
432 pointers.reset(new char *[count + 1]);
433 pointers[count] = nullptr;
434
435 const auto end = env.end();
436 auto it = env.begin();
437 for (qsizetype i = 0; it != end; ++it, ++i) {
438 // we abuse the pointer array to store offsets first (QByteArray will
439 // reallocate, after all)
440 pointers[i] = reinterpret_cast<char *>(data.size());
441
442 data += it.key();
443 data += '=';
444 data += it->bytes();
445 data += '\0';
446 }
447
448 updatePointers(count);
449}
450
451void QChildProcess::CharPointerList::updatePointers(qsizetype count)
452{
453 char *const base = const_cast<char *>(data.constBegin());
454 for (qsizetype i = 0; i < count; ++i)
455 pointers[i] = base + qptrdiff(pointers[i]);
456}
457} // anonymous namespace
458
459static bool qt_pollfd_check(const pollfd &pfd, short revents)
460{
461 return pfd.fd >= 0 && (pfd.revents & (revents | POLLHUP | POLLERR | POLLNVAL)) != 0;
462}
463
464static int qt_create_pipe(int *pipe)
465{
466 if (pipe[0] != -1)
467 qt_safe_close(pipe[0]);
468 if (pipe[1] != -1)
469 qt_safe_close(pipe[1]);
470 int pipe_ret = qt_safe_pipe(pipe);
471 if (pipe_ret != 0) {
472 QScopedValueRollback rollback(errno);
473 qErrnoWarning("QProcess: Cannot create pipe");
474 }
475 return pipe_ret;
476}
477
478void QProcessPrivate::destroyPipe(int *pipe)
479{
480 if (pipe[1] != -1) {
481 qt_safe_close(pipe[1]);
482 pipe[1] = -1;
483 }
484 if (pipe[0] != -1) {
485 qt_safe_close(pipe[0]);
486 pipe[0] = -1;
487 }
488}
489
490void QProcessPrivate::closeChannel(Channel *channel)
491{
492 delete channel->notifier;
493 channel->notifier = nullptr;
494
495 destroyPipe(channel->pipe);
496}
497
498void QProcessPrivate::cleanup()
499{
500 q_func()->setProcessState(QProcess::NotRunning);
501
502 closeChannels();
503 delete stateNotifier;
504 stateNotifier = nullptr;
505 destroyPipe(childStartedPipe);
506 pid = 0;
507 if (forkfd != -1) {
508 qt_safe_close(forkfd);
509 forkfd = -1;
510 }
511}
512
513/*
514 Create the pipes to a QProcessPrivate::Channel.
515*/
516bool QProcessPrivate::openChannel(Channel &channel)
517{
518 Q_Q(QProcess);
519
520 if (channel.type == Channel::Normal) {
521 // we're piping this channel to our own process
522 if (qt_create_pipe(channel.pipe) != 0) {
523 setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall("pipe"));
524 return false;
525 }
526
527 // create the socket notifiers
528 if (threadData.loadRelaxed()->hasEventDispatcher()) {
529 if (&channel == &stdinChannel) {
530 channel.notifier = new QSocketNotifier(QSocketNotifier::Write, q);
531 channel.notifier->setSocket(channel.pipe[1]);
532 QObjectPrivate::connect(channel.notifier, &QSocketNotifier::activated, this,
533 &QProcessPrivate::_q_canWrite);
534 } else {
535 channel.notifier = new QSocketNotifier(QSocketNotifier::Read, q);
536 channel.notifier->setSocket(channel.pipe[0]);
537 auto receiver = &channel == &stdoutChannel ? &QProcessPrivate::_q_canReadStandardOutput
538 : &QProcessPrivate::_q_canReadStandardError;
539 QObjectPrivate::connect(channel.notifier, &QSocketNotifier::activated, this,
540 receiver);
541 }
542 }
543
544 return true;
545 } else if (channel.type == Channel::Redirect) {
546 // we're redirecting the channel to/from a file
547 QByteArray fname = QFile::encodeName(channel.file);
548
549 if (&channel == &stdinChannel) {
550 // try to open in read-only mode
551 channel.pipe[1] = -1;
552 if ( (channel.pipe[0] = qt_safe_open(fname, O_RDONLY)) != -1)
553 return true; // success
554 setErrorAndEmit(QProcess::FailedToStart,
555 QProcess::tr("Could not open input redirection for reading"));
556 } else {
557 int mode = O_WRONLY | O_CREAT;
558 if (channel.append)
559 mode |= O_APPEND;
560 else
561 mode |= O_TRUNC;
562
563 channel.pipe[0] = -1;
564 if ( (channel.pipe[1] = qt_safe_open(fname, mode, 0666)) != -1)
565 return true; // success
566
567 setErrorAndEmit(QProcess::FailedToStart,
568 QProcess::tr("Could not open input redirection for reading"));
569 }
570 return false;
571 } else {
572 Q_ASSERT_X(channel.process, "QProcess::start", "Internal error");
573
574 Channel *source;
575 Channel *sink;
576
577 if (channel.type == Channel::PipeSource) {
578 // we are the source
579 source = &channel;
580 sink = &channel.process->stdinChannel;
581
582 Q_ASSERT(source == &stdoutChannel);
583 Q_ASSERT(sink->process == this && sink->type == Channel::PipeSink);
584 } else {
585 // we are the sink;
586 source = &channel.process->stdoutChannel;
587 sink = &channel;
588
589 Q_ASSERT(sink == &stdinChannel);
590 Q_ASSERT(source->process == this && source->type == Channel::PipeSource);
591 }
592
593 if (source->pipe[1] != INVALID_Q_PIPE || sink->pipe[0] != INVALID_Q_PIPE) {
594 // already created, do nothing
595 return true;
596 } else {
597 Q_ASSERT(source->pipe[0] == INVALID_Q_PIPE && source->pipe[1] == INVALID_Q_PIPE);
598 Q_ASSERT(sink->pipe[0] == INVALID_Q_PIPE && sink->pipe[1] == INVALID_Q_PIPE);
599
600 Q_PIPE pipe[2] = { -1, -1 };
601 if (qt_create_pipe(pipe) != 0) {
602 setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall("pipe"));
603 return false;
604 }
605 sink->pipe[0] = pipe[0];
606 source->pipe[1] = pipe[1];
607
608 return true;
609 }
610 }
611}
612
613void QProcessPrivate::commitChannels() const
614{
615 // copy the stdin socket if asked to (without closing on exec)
616 if (stdinChannel.pipe[0] != INVALID_Q_PIPE)
617 qt_safe_dup2(stdinChannel.pipe[0], STDIN_FILENO, 0);
618
619 // copy the stdout and stderr if asked to
620 if (stdoutChannel.pipe[1] != INVALID_Q_PIPE)
621 qt_safe_dup2(stdoutChannel.pipe[1], STDOUT_FILENO, 0);
622 if (stderrChannel.pipe[1] != INVALID_Q_PIPE) {
623 qt_safe_dup2(stderrChannel.pipe[1], STDERR_FILENO, 0);
624 } else {
625 // merge stdout and stderr if asked to
626 if (processChannelMode == QProcess::MergedChannels)
627 qt_safe_dup2(STDOUT_FILENO, STDERR_FILENO, 0);
628 }
629}
630
631inline QString QChildProcess::resolveExecutable(const QString &program)
632{
633#ifdef Q_OS_DARWIN
634 // allow invoking of .app bundles on the Mac.
635 QFileInfo fileInfo(program);
636 if (program.endsWith(".app"_L1) && fileInfo.isDir()) {
637 QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0,
638 QCFString(fileInfo.absoluteFilePath()),
639 kCFURLPOSIXPathStyle, true);
640 {
641 // CFBundle is not reentrant, since CFBundleCreate might return a reference
642 // to a cached bundle object. Protect the bundle calls with a mutex lock.
643 Q_CONSTINIT static QBasicMutex cfbundleMutex;
644 const auto locker = qt_scoped_lock(cfbundleMutex);
645 QCFType<CFBundleRef> bundle = CFBundleCreate(0, url);
646 // 'executableURL' can be either relative or absolute ...
647 QCFType<CFURLRef> executableURL = CFBundleCopyExecutableURL(bundle);
648 // not to depend on caching - make sure it's always absolute.
649 url = CFURLCopyAbsoluteURL(executableURL);
650 }
651 if (url) {
652 const QCFString str = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
653 return QString::fromCFString(str);
654 }
655 }
656#endif
657
658 if (!program.contains(u'/')) {
659 // findExecutable() returns its argument if it's an absolute path,
660 // otherwise it searches $PATH; returns empty if not found (we handle
661 // that case much later)
662 return QStandardPaths::findExecutable(program);
663 }
664 return program;
665}
666
667extern "C" {
668__attribute__((weak)) pid_t __interceptor_vfork();
669}
670
671inline bool globalUsingVfork() noexcept
672{
673#if defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer)
674 // ASan writes to global memory, so we mustn't use vfork().
675 return false;
676#endif
677#if defined(__SANITIZE_THREAD__) || __has_feature(thread_sanitizer)
678 // Ditto, apparently
679 return false;
680#endif
681#if defined(Q_OS_LINUX) && !QT_CONFIG(forkfd_pidfd)
682 // some broken environments are known to have problems with the new Linux
683 // API, so we have a way for users to opt-out during configure time (see
684 // QTBUG-86285)
685 return false;
686#endif
687#if defined(Q_OS_DARWIN)
688 // Using vfork() for startDetached() is causing problems. We don't know
689 // why: without the tools to investigate why it happens, we didn't bother.
690 return false;
691#endif
692#if defined(Q_OS_CYGWIN)
693 // Fails to link Qt6Core, so we avoid that..
694 return false;
695#endif
696
697 // Dynamically detect whether libasan or libtsan are loaded into the
698 // process' memory. We need this because the user's code may be compiled
699 // with ASan or TSan, but not Qt.
700 return __interceptor_vfork == nullptr;
701}
702
703inline bool QChildProcess::usingVfork() const noexcept
704{
705 if (!globalUsingVfork())
706 return false;
707
708 if (!d->unixExtras || !d->unixExtras->childProcessModifier)
709 return true; // no modifier was supplied
710
711 // if a modifier was supplied, use fork() unless the user opts in to
712 // vfork()
713 auto flags = d->unixExtras->processParameters.flags;
714 return flags.testFlag(QProcess::UnixProcessFlag::UseVFork);
715}
716
717#ifdef QT_BUILD_INTERNAL
718Q_AUTOTEST_EXPORT bool _qprocessUsingVfork() noexcept
719{
720 return globalUsingVfork();
721}
722#endif
723
724void QProcessPrivate::startProcess()
725{
726 Q_Q(QProcess);
727 q->setProcessState(QProcess::Starting);
728
729#if defined (QPROCESS_DEBUG)
730 qDebug("QProcessPrivate::startProcess()");
731#endif
732
733 // Initialize pipes
734 if (!openChannels()) {
735 // openChannel sets the error string
736 Q_ASSERT(!errorString.isEmpty());
737 cleanup();
738 return;
739 }
740 if (qt_create_pipe(childStartedPipe) != 0) {
741 setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall("pipe"));
742 cleanup();
743 return;
744 }
745
746 if (threadData.loadRelaxed()->hasEventDispatcher()) {
747 // Set up to notify about startup completion (and premature death).
748 // Once the process has started successfully, we reconfigure the
749 // notifier to watch the fork_fd for expected death.
750 stateNotifier = new QSocketNotifier(childStartedPipe[0],
751 QSocketNotifier::Read, q);
752 QObjectPrivate::connect(stateNotifier, &QSocketNotifier::activated, this,
753 &QProcessPrivate::_q_startupNotification);
754 }
755
756 // Prepare the arguments and the environment
757 QChildProcess childProcess(this);
758 if (!childProcess.ok()) {
759 Q_ASSERT(processError != QProcess::UnknownError);
760 return;
761 }
762
763 // Start the child.
764 forkfd = childProcess.startChild(&pid);
765 int lastForkErrno = errno;
766
767 if (forkfd == -1) {
768 // Cleanup, report error and return
769 childProcess.cleanup();
770#if defined (QPROCESS_DEBUG)
771 qDebug("fork failed: %ls", qUtf16Printable(qt_error_string(lastForkErrno)));
772#endif
773 q->setProcessState(QProcess::NotRunning);
774 setErrorAndEmit(QProcess::FailedToStart,
775 QProcess::tr("Resource error (fork failure): %1").arg(qt_error_string(lastForkErrno)));
776 cleanup();
777 return;
778 }
779
780 Q_ASSERT(pid > 0);
781
782 // parent
783 // close the ends we don't use and make all pipes non-blocking
784 qt_safe_close(childStartedPipe[1]);
785 childStartedPipe[1] = -1;
786
787 if (stdinChannel.pipe[0] != -1) {
788 qt_safe_close(stdinChannel.pipe[0]);
789 stdinChannel.pipe[0] = -1;
790 }
791
792 if (stdinChannel.pipe[1] != -1)
793 ::fcntl(stdinChannel.pipe[1], F_SETFL, ::fcntl(stdinChannel.pipe[1], F_GETFL) | O_NONBLOCK);
794
795 if (stdoutChannel.pipe[1] != -1) {
796 qt_safe_close(stdoutChannel.pipe[1]);
797 stdoutChannel.pipe[1] = -1;
798 }
799
800 if (stdoutChannel.pipe[0] != -1)
801 ::fcntl(stdoutChannel.pipe[0], F_SETFL, ::fcntl(stdoutChannel.pipe[0], F_GETFL) | O_NONBLOCK);
802
803 if (stderrChannel.pipe[1] != -1) {
804 qt_safe_close(stderrChannel.pipe[1]);
805 stderrChannel.pipe[1] = -1;
806 }
807 if (stderrChannel.pipe[0] != -1)
808 ::fcntl(stderrChannel.pipe[0], F_SETFL, ::fcntl(stderrChannel.pipe[0], F_GETFL) | O_NONBLOCK);
809}
810
811Q_NORETURN void
812failChildProcess(const QProcessPrivate *d, const char *description, int code) noexcept
813{
814 ChildError error = {};
815 error.code = code;
816 qstrncpy(error.function, description, sizeof(error.function));
817 qt_safe_write(d->childStartedPipe[1], &error, sizeof(error));
818 _exit(-1);
819}
820
821void QProcess::failChildProcessModifier(const char *description, int error) noexcept
822{
823 // We signal user errors with negative errnos
824 failChildProcess(d_func(), description, -error);
825}
826
827// See IMPORTANT notice below
828static const char *applyProcessParameters(const QProcess::UnixProcessParameters &params)
829{
830 // Apply Unix signal handler parameters.
831 // We don't expect signal() to fail, so we ignore its return value
832 bool ignore_sigpipe = params.flags.testFlag(QProcess::UnixProcessFlag::IgnoreSigPipe);
833 if (ignore_sigpipe)
834 QtVforkSafe::change_sigpipe(SIG_IGN);
835 if (params.flags.testFlag(QProcess::UnixProcessFlag::ResetSignalHandlers)) {
836 struct sigaction sa = {};
837 sa.sa_handler = SIG_DFL;
838 for (int sig = 1; sig < NSIG; ++sig) {
839 if (!ignore_sigpipe || sig != SIGPIPE)
840 QtVforkSafe::sigaction(sig, &sa, nullptr);
841 }
842
843 // and unmask all signals
844 sigset_t set;
845 sigemptyset(&set);
846 sigprocmask(SIG_SETMASK, &set, nullptr);
847 }
848
849 // Close all file descriptors above stderr.
850 // This isn't expected to fail, so we ignore close()'s return value.
851 if (params.flags.testFlag(QProcess::UnixProcessFlag::CloseFileDescriptors)) {
852 int r = -1;
853 int fd = qMax(STDERR_FILENO + 1, params.lowestFileDescriptorToClose);
854#ifdef CLOSE_RANGE_CLOEXEC
855 // Mark the file descriptors for closing upon execve() - we delay
856 // closing so we don't close the ones QProcess needs for itself.
857 // On FreeBSD, this probably won't fail.
858 // On Linux, this will fail with ENOSYS before kernel 5.9 and EINVAL
859 // before 5.11.
860 r = close_range(fd, INT_MAX, CLOSE_RANGE_CLOEXEC);
861#endif
862 if (r == -1) {
863 // We *could* read /dev/fd to find out what file descriptors are
864 // open, but we won't. We CANNOT use opendir() here because it
865 // allocates memory. Using getdents(2) plus either strtoul() or
866 // std::from_chars() would be acceptable.
867 int max_fd = INT_MAX;
868 if (struct rlimit limit; getrlimit(RLIMIT_NOFILE, &limit) == 0)
869 max_fd = limit.rlim_cur;
870 for ( ; fd < max_fd; ++fd)
871 fcntl(fd, F_SETFD, FD_CLOEXEC);
872 }
873 }
874
875 // Apply session and process group settings. This may fail.
876 if (params.flags.testFlag(QProcess::UnixProcessFlag::CreateNewSession)) {
877 if (setsid() < 0)
878 return "setsid";
879 }
880
881 // Disconnect from the controlling TTY. This probably won't fail. Must be
882 // done after the session settings from above.
883 if (params.flags.testFlag(QProcess::UnixProcessFlag::DisconnectControllingTerminal)) {
884#ifdef TIOCNOTTY
885 if (int fd = open(_PATH_TTY, O_RDONLY | O_NOCTTY); fd >= 0) {
886 // we still have a controlling TTY; give it up
887 int r = ioctl(fd, TIOCNOTTY);
888 int savedErrno = errno;
889 close(fd);
890 if (r != 0) {
891 errno = savedErrno;
892 return "ioctl";
893 }
894 }
895#endif
896 }
897
898 // Disable core dumps near the end. This isn't expected to fail.
899 if (params.flags.testFlag(QProcess::UnixProcessFlag::DisableCoreDumps)) {
900 if (struct rlimit lim; getrlimit(RLIMIT_CORE, &lim) == 0 && lim.rlim_cur) {
901 // We'll leave rlim_max untouched, so the child can set it back if it
902 // wants to. We don't expect setrlimit() to fail, so we ignore its
903 // return value.
904 lim.rlim_cur = 0;
905 (void) setrlimit(RLIMIT_CORE, &lim);
906 }
907 }
908
909 // Apply UID and GID parameters last. This isn't expected to fail either:
910 // either we're trying to impersonate what we already are, or we're EUID or
911 // EGID root, in which case we are allowed to do this.
912 if (params.flags.testFlag(QProcess::UnixProcessFlag::ResetIds)) {
913 int r = setgid(getgid());
914 r = setuid(getuid());
915 (void) r;
916 }
917
918 return nullptr;
919}
920
921// the noexcept here adds an extra layer of protection
922static void callChildProcessModifier(const QProcessPrivate *d) noexcept
923{
924 QT_TRY {
925 if (d->unixExtras->childProcessModifier)
926 d->unixExtras->childProcessModifier();
927 } QT_CATCH (std::exception &e) {
928 failChildProcess(d, e.what(), FakeErrnoForThrow);
929 } QT_CATCH (...) {
930 failChildProcess(d, "throw", FakeErrnoForThrow);
931 }
932}
933
934// IMPORTANT:
935//
936// This function is called in a vfork() context on some OSes (notably, Linux
937// with forkfd), so it MUST NOT modify any non-local variable because it's
938// still sharing memory with the parent process.
939void QChildProcess::startProcess() const noexcept
940{
941 // Render channels configuration.
942 d->commitChannels();
943
944 // make sure this fd is closed if execv() succeeds
945 qt_safe_close(d->childStartedPipe[0]);
946
947 // enter the working directory
948 if (workingDirectory >= 0 && fchdir(workingDirectory) == -1)
949 failChildProcess(d, "fchdir", errno);
950
951 bool sigpipeHandled = false;
952 bool sigmaskHandled = false;
953 if (d->unixExtras) {
954 // FIRST we call the user modifier function, before we dropping
955 // privileges or closing non-standard file descriptors
956 callChildProcessModifier(d);
957
958 // then we apply our other user-provided parameters
959 if (const char *what = applyProcessParameters(d->unixExtras->processParameters))
960 failChildProcess(d, what, errno);
961
962 auto flags = d->unixExtras->processParameters.flags;
963 using P = QProcess::UnixProcessFlag;
964 sigpipeHandled = flags.testAnyFlags(P::ResetSignalHandlers | P::IgnoreSigPipe);
965 sigmaskHandled = flags.testFlag(P::ResetSignalHandlers);
966 }
967 if (!sigpipeHandled) {
968 // reset the signal that we ignored
969 QtVforkSafe::change_sigpipe(SIG_DFL); // reset the signal that we ignored
970 }
971 if (!sigmaskHandled) {
972 // restore the signal mask from the parent, if applyProcessParameters()
973 // hasn't completely reset it
974 restoreSignalMask();
975 }
976
977 // execute the process
978 if (!envp.pointers)
979 qt_safe_execv(argv[0], argv);
980 else
981 qt_safe_execve(argv[0], argv, envp);
982 failChildProcess(d, "execve", errno);
983}
984
985bool QProcessPrivate::processStarted(QString *errorMessage)
986{
987 Q_Q(QProcess);
988
989 ChildError buf;
990 ssize_t ret = qt_safe_read(childStartedPipe[0], &buf, sizeof(buf));
991
992 if (stateNotifier) {
993 stateNotifier->setEnabled(false);
994 stateNotifier->disconnect(q);
995 }
996 qt_safe_close(childStartedPipe[0]);
997 childStartedPipe[0] = -1;
998
999#if defined (QPROCESS_DEBUG)
1000 qDebug("QProcessPrivate::processStarted() == %s", ret <= 0 ? "true" : "false");
1001#endif
1002
1003 if (ret <= 0) { // process successfully started
1004 if (stateNotifier) {
1005 QObjectPrivate::connect(stateNotifier, &QSocketNotifier::activated, this,
1006 &QProcessPrivate::_q_processDied);
1007 stateNotifier->setSocket(forkfd);
1008 stateNotifier->setEnabled(true);
1009 }
1010 if (stdoutChannel.notifier)
1011 stdoutChannel.notifier->setEnabled(true);
1012 if (stderrChannel.notifier)
1013 stderrChannel.notifier->setEnabled(true);
1014
1015 return true;
1016 }
1017
1018 // did we read an error message?
1019 if (errorMessage)
1020 *errorMessage = startFailureErrorMessage(buf, ret);
1021
1022 return false;
1023}
1024
1025qint64 QProcessPrivate::bytesAvailableInChannel(const Channel *channel) const
1026{
1027 Q_ASSERT(channel->pipe[0] != INVALID_Q_PIPE);
1028 int nbytes = 0;
1029 qint64 available = 0;
1030 if (::ioctl(channel->pipe[0], FIONREAD, (char *) &nbytes) >= 0)
1031 available = (qint64) nbytes;
1032#if defined (QPROCESS_DEBUG)
1033 qDebug("QProcessPrivate::bytesAvailableInChannel(%d) == %lld", int(channel - &stdinChannel), available);
1034#endif
1035 return available;
1036}
1037
1038qint64 QProcessPrivate::readFromChannel(const Channel *channel, char *data, qint64 maxlen)
1039{
1040 Q_ASSERT(channel->pipe[0] != INVALID_Q_PIPE);
1041 qint64 bytesRead = qt_safe_read(channel->pipe[0], data, maxlen);
1042#if defined QPROCESS_DEBUG
1043 int save_errno = errno;
1044 qDebug("QProcessPrivate::readFromChannel(%d, %p \"%s\", %lld) == %lld",
1045 int(channel - &stdinChannel),
1046 data, QtDebugUtils::toPrintable(data, bytesRead, 16).constData(), maxlen, bytesRead);
1047 errno = save_errno;
1048#endif
1049 if (bytesRead == -1 && errno == EWOULDBLOCK)
1050 return -2;
1051 return bytesRead;
1052}
1053
1054/*! \reimp
1055*/
1056qint64 QProcess::writeData(const char *data, qint64 len)
1057{
1058 Q_D(QProcess);
1059
1060 if (d->stdinChannel.closed) {
1061#if defined QPROCESS_DEBUG
1062 qDebug("QProcess::writeData(%p \"%s\", %lld) == 0 (write channel closing)",
1063 data, QtDebugUtils::toPrintable(data, len, 16).constData(), len);
1064#endif
1065 return 0;
1066 }
1067
1068 d->write(data, len);
1069 if (d->stdinChannel.notifier)
1070 d->stdinChannel.notifier->setEnabled(true);
1071
1072#if defined QPROCESS_DEBUG
1073 qDebug("QProcess::writeData(%p \"%s\", %lld) == %lld (written to buffer)",
1074 data, QtDebugUtils::toPrintable(data, len, 16).constData(), len, len);
1075#endif
1076 return len;
1077}
1078
1079bool QProcessPrivate::_q_canWrite()
1080{
1081 if (writeBuffer.isEmpty()) {
1082 if (stdinChannel.notifier)
1083 stdinChannel.notifier->setEnabled(false);
1084#if defined QPROCESS_DEBUG
1085 qDebug("QProcessPrivate::canWrite(), not writing anything (empty write buffer).");
1086#endif
1087 return false;
1088 }
1089
1090 const bool writeSucceeded = writeToStdin();
1091
1092 if (writeBuffer.isEmpty() && stdinChannel.closed)
1093 closeWriteChannel();
1094 else if (stdinChannel.notifier)
1095 stdinChannel.notifier->setEnabled(!writeBuffer.isEmpty());
1096
1097 return writeSucceeded;
1098}
1099
1100bool QProcessPrivate::writeToStdin()
1101{
1102 const char *data = writeBuffer.readPointer();
1103 const qint64 bytesToWrite = writeBuffer.nextDataBlockSize();
1104
1105 qint64 written = qt_safe_write_nosignal(stdinChannel.pipe[1], data, bytesToWrite);
1106#if defined QPROCESS_DEBUG
1107 qDebug("QProcessPrivate::writeToStdin(), write(%p \"%s\", %lld) == %lld", data,
1108 QtDebugUtils::toPrintable(data, bytesToWrite, 16).constData(), bytesToWrite, written);
1109 if (written == -1)
1110 qDebug("QProcessPrivate::writeToStdin(), failed to write (%ls)", qUtf16Printable(qt_error_string(errno)));
1111#endif
1112 if (written == -1) {
1113 // If the O_NONBLOCK flag is set and If some data can be written without blocking
1114 // the process, write() will transfer what it can and return the number of bytes written.
1115 // Otherwise, it will return -1 and set errno to EAGAIN
1116 if (errno == EAGAIN)
1117 return true;
1118
1119 closeChannel(&stdinChannel);
1120 setErrorAndEmit(QProcess::WriteError);
1121 return false;
1122 }
1123 writeBuffer.free(written);
1124 if (!emittedBytesWritten && written != 0) {
1125 emittedBytesWritten = true;
1126 emit q_func()->bytesWritten(written);
1127 emittedBytesWritten = false;
1128 }
1129 return true;
1130}
1131
1132void QProcessPrivate::terminateProcess()
1133{
1134#if defined (QPROCESS_DEBUG)
1135 qDebug("QProcessPrivate::terminateProcess() pid=%jd", intmax_t(pid));
1136#endif
1137 if (pid > 0)
1138 ::kill(pid, SIGTERM);
1139}
1140
1141void QProcessPrivate::killProcess()
1142{
1143#if defined (QPROCESS_DEBUG)
1144 qDebug("QProcessPrivate::killProcess() pid=%jd", intmax_t(pid));
1145#endif
1146 if (pid > 0)
1147 ::kill(pid, SIGKILL);
1148}
1149
1150bool QProcessPrivate::waitForStarted(const QDeadlineTimer &deadline)
1151{
1152#if defined (QPROCESS_DEBUG)
1153 const qint64 msecs = deadline.remainingTime();
1154 qDebug("QProcessPrivate::waitForStarted(%lld) waiting for child to start (fd = %d)",
1155 msecs, childStartedPipe[0]);
1156#endif
1157
1158 pollfd pfd = qt_make_pollfd(childStartedPipe[0], POLLIN);
1159
1160 if (qt_safe_poll(&pfd, 1, deadline) == 0) {
1161 setError(QProcess::Timedout);
1162#if defined (QPROCESS_DEBUG)
1163 qDebug("QProcessPrivate::waitForStarted(%lld) == false (timed out)", msecs);
1164#endif
1165 return false;
1166 }
1167
1168 bool startedEmitted = _q_startupNotification();
1169#if defined (QPROCESS_DEBUG)
1170 qDebug("QProcessPrivate::waitForStarted() == %s", startedEmitted ? "true" : "false");
1171#endif
1172 return startedEmitted;
1173}
1174
1175bool QProcessPrivate::waitForReadyRead(const QDeadlineTimer &deadline)
1176{
1177#if defined (QPROCESS_DEBUG)
1178 qDebug("QProcessPrivate::waitForReadyRead(%lld)", deadline.remainingTime());
1179#endif
1180
1181 forever {
1182 QProcessPoller poller(*this);
1183
1184 int ret = poller.poll(deadline);
1185
1186 if (ret < 0) {
1187 break;
1188 }
1189 if (ret == 0) {
1190 setError(QProcess::Timedout);
1191 return false;
1192 }
1193
1194 // This calls QProcessPrivate::tryReadFromChannel(), which returns true
1195 // if we emitted readyRead() signal on the current read channel.
1196 bool readyReadEmitted = false;
1197 if (qt_pollfd_check(poller.stdoutPipe(), POLLIN) && _q_canReadStandardOutput())
1198 readyReadEmitted = true;
1199 if (qt_pollfd_check(poller.stderrPipe(), POLLIN) && _q_canReadStandardError())
1200 readyReadEmitted = true;
1201
1202 if (readyReadEmitted)
1203 return true;
1204
1205 if (qt_pollfd_check(poller.stdinPipe(), POLLOUT))
1206 _q_canWrite();
1207
1208 // Signals triggered by I/O may have stopped this process:
1209 if (processState == QProcess::NotRunning)
1210 return false;
1211
1212 // We do this after checking the pipes, so we cannot reach it as long
1213 // as there is any data left to be read from an already dead process.
1214 if (qt_pollfd_check(poller.forkfd(), POLLIN)) {
1215 processFinished();
1216 return false;
1217 }
1218 }
1219 return false;
1220}
1221
1222bool QProcessPrivate::waitForBytesWritten(const QDeadlineTimer &deadline)
1223{
1224#if defined (QPROCESS_DEBUG)
1225 qDebug("QProcessPrivate::waitForBytesWritten(%lld)", deadline.remainingTime());
1226#endif
1227
1228 while (!writeBuffer.isEmpty()) {
1229 QProcessPoller poller(*this);
1230
1231 int ret = poller.poll(deadline);
1232
1233 if (ret < 0) {
1234 break;
1235 }
1236
1237 if (ret == 0) {
1238 setError(QProcess::Timedout);
1239 return false;
1240 }
1241
1242 if (qt_pollfd_check(poller.stdinPipe(), POLLOUT))
1243 return _q_canWrite();
1244
1245 if (qt_pollfd_check(poller.stdoutPipe(), POLLIN))
1246 _q_canReadStandardOutput();
1247
1248 if (qt_pollfd_check(poller.stderrPipe(), POLLIN))
1249 _q_canReadStandardError();
1250
1251 // Signals triggered by I/O may have stopped this process:
1252 if (processState == QProcess::NotRunning)
1253 return false;
1254
1255 if (qt_pollfd_check(poller.forkfd(), POLLIN)) {
1256 processFinished();
1257 return false;
1258 }
1259 }
1260
1261 return false;
1262}
1263
1264bool QProcessPrivate::waitForFinished(const QDeadlineTimer &deadline)
1265{
1266#if defined (QPROCESS_DEBUG)
1267 qDebug("QProcessPrivate::waitForFinished(%lld)", deadline.remainingTime());
1268#endif
1269
1270 forever {
1271 QProcessPoller poller(*this);
1272
1273 int ret = poller.poll(deadline);
1274
1275 if (ret < 0) {
1276 break;
1277 }
1278 if (ret == 0) {
1279 setError(QProcess::Timedout);
1280 return false;
1281 }
1282
1283 if (qt_pollfd_check(poller.stdinPipe(), POLLOUT))
1284 _q_canWrite();
1285
1286 if (qt_pollfd_check(poller.stdoutPipe(), POLLIN))
1287 _q_canReadStandardOutput();
1288
1289 if (qt_pollfd_check(poller.stderrPipe(), POLLIN))
1290 _q_canReadStandardError();
1291
1292 // Signals triggered by I/O may have stopped this process:
1293 if (processState == QProcess::NotRunning)
1294 return true;
1295
1296 if (qt_pollfd_check(poller.forkfd(), POLLIN)) {
1297 processFinished();
1298 return true;
1299 }
1300 }
1301 return false;
1302}
1303
1304void QProcessPrivate::waitForDeadChild()
1305{
1306 Q_ASSERT(forkfd != -1);
1307
1308 // read the process information from our fd
1309 forkfd_info info = {}; // Silence -Wmaybe-uninitialized; Thiago says forkfd_wait cannot fail here
1310 // (QTBUG-119081)
1311 int ret;
1312 QT_EINTR_LOOP(ret, forkfd_wait(forkfd, &info, nullptr));
1313
1314 exitCode = info.status;
1315 exitStatus = info.code == CLD_EXITED ? QProcess::NormalExit : QProcess::CrashExit;
1316
1317 delete stateNotifier;
1318 stateNotifier = nullptr;
1319
1320 QT_EINTR_LOOP(ret, forkfd_close(forkfd));
1321 forkfd = -1; // Child is dead, don't try to kill it anymore
1322
1323#if defined QPROCESS_DEBUG
1324 qDebug() << "QProcessPrivate::waitForDeadChild() dead with exitCode"
1325 << exitCode << ", crashed?" << (info.code != CLD_EXITED);
1326#endif
1327}
1328
1329bool QProcessPrivate::startDetached(qint64 *pid)
1330{
1331 AutoPipe startedPipe, pidPipe;
1332 if (!startedPipe || !pidPipe) {
1333 setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall("pipe"));
1334 return false;
1335 }
1336
1337 if (!openChannelsForDetached()) {
1338 // openChannel sets the error string
1339 closeChannels();
1340 return false;
1341 }
1342
1343 // see startProcess() for more information
1344 QChildProcess childProcess(this);
1345 if (!childProcess.ok()) {
1346 Q_ASSERT(processError != QProcess::UnknownError);
1347 return false;
1348 }
1349
1350 childStartedPipe[1] = startedPipe[1]; // for failChildProcess()
1351 pid_t childPid = childProcess.doFork([&] {
1352 ::setsid();
1353
1354 qt_safe_close(startedPipe[0]);
1355 qt_safe_close(pidPipe[0]);
1356
1357 pid_t doubleForkPid;
1358 if (childProcess.startChild(&doubleForkPid) == -1)
1359 failChildProcess(this, "fork", errno);
1360
1361 // success
1362 qt_safe_write(pidPipe[1], &doubleForkPid, sizeof(pid_t));
1363 return 0;
1364 });
1365 childStartedPipe[1] = -1;
1366
1367 int savedErrno = errno;
1368 closeChannels();
1369
1370 if (childPid == -1) {
1371 childProcess.cleanup();
1372 setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall("fork", savedErrno));
1373 return false;
1374 }
1375
1376 // close the writing ends of the pipes so we can properly get EOFs
1377 qt_safe_close(pidPipe[1]);
1378 qt_safe_close(startedPipe[1]);
1379 pidPipe[1] = startedPipe[1] = -1;
1380
1381 // This read() will block until we're cleared to proceed. If it returns 0
1382 // (EOF), it means the direct child has exited and the grandchild
1383 // successfully execve()'d the target process. If it returns any positive
1384 // result, it means one of the two children wrote an error result. Negative
1385 // values should not happen.
1386 ChildError childStatus;
1387 ssize_t startResult = qt_safe_read(startedPipe[0], &childStatus, sizeof(childStatus));
1388
1389 // reap the intermediate child
1390 int result;
1391 qt_safe_waitpid(childPid, &result, 0);
1392
1393 bool success = (startResult == 0); // nothing written -> no error
1394 if (success && pid) {
1395 pid_t actualPid;
1396 if (qt_safe_read(pidPipe[0], &actualPid, sizeof(pid_t)) != sizeof(pid_t))
1397 actualPid = 0; // this shouldn't happen!
1398 *pid = actualPid;
1399 } else if (!success) {
1400 if (pid)
1401 *pid = -1;
1402 childProcess.cleanup();
1403 setErrorAndEmit(QProcess::FailedToStart,
1404 startFailureErrorMessage(childStatus, startResult));
1405 }
1406 return success;
1407}
1408
1409#endif // QT_CONFIG(process)
1410
1411QT_END_NAMESPACE
#define __has_include(x)
#define _PATH_TTY
#define _PATH_DEV
char ** environ