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