9#include <private/qdebug_p.h>
10#include "qplatformdefs.h"
15#include "private/qcore_unix_p.h"
16#include "private/qlocking_p.h"
19#include <private/qcore_mac_p.h>
22#include <private/qcoreapplication_p.h>
23#include <private/qthread_p.h>
29#include <qsocketnotifier.h>
33# include <sys/neutrino.h>
40#include <sys/resource.h>
56# define _PATH_DEV "/dev/"
59# define _PATH_TTY _PATH_DEV "tty"
69using namespace Qt::StringLiterals;
71#if !defined(Q_OS_DARWIN)
73QProcessEnvironment QProcessEnvironment::systemEnvironment()
75 QProcessEnvironment env;
77 for (
int count = 0; (entry = environ[count]); ++count) {
78 const char *equal = strchr(entry,
'=');
82 QByteArray name(entry, equal - entry);
83 QByteArray value(equal + 1);
84 env.d->vars.insert(QProcessEnvironmentPrivate::Key(name),
85 QProcessEnvironmentPrivate::Value(value));
94namespace QtVforkSafe {
115# define LIBC_PREFIX __libc_
116#elif defined(Q_OS_FREEBSD)
118# define 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));
128# define DECLARE_FUNCTIONS(NAME) using ::NAME;
132DECLARE_FUNCTIONS(sigaction)
136#undef DECLARE_FUNCTIONS
139static void change_sigpipe(
decltype(SIG_DFL) new_handler)
142 memset(&sa, 0,
sizeof(sa));
143 sa.sa_handler = new_handler;
144 sigaction(SIGPIPE, &sa,
nullptr);
148static int opendirfd(QByteArray encodedName)
153 if (encodedName !=
"/" && !encodedName.endsWith(
"/."))
155 return qt_safe_open(encodedName, QT_OPEN_RDONLY | O_DIRECTORY | O_PATH);
161 int pipe[2] = { -1, -1 };
162 AutoPipe(
int flags = 0)
164 qt_safe_pipe(pipe, flags);
168 for (
int fd : pipe) {
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]; }
182 char function[_POSIX_PIPE_BUF -
sizeof(code)];
184static_assert(std::is_trivially_copy_constructible_v<ChildError>);
186static_assert(PIPE_BUF >=
sizeof(ChildError));
191static constexpr int FakeErrnoForThrow = std::numeric_limits<
int>::max();
193static QString errorMessageForSyscall(QUtf8StringView fnName,
int errnoCode = -1)
195 QString msg = qt_error_string(errnoCode);
196 return QProcess::tr(
"Child process set up failed: %1: %2").arg(fnName, std::move(msg));
199static QString startFailureErrorMessage(ChildError &err, [[maybe_unused]] ssize_t bytesRead)
203 Q_ASSERT(bytesRead ==
sizeof(err));
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")
211 return QProcess::tr(
"Child process modifier reported error: %1")
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);
221 QProcessPoller(
const QProcessPrivate &proc);
223 int poll(
const QDeadlineTimer &deadline);
225 pollfd &stdinPipe() {
return pfds[0]; }
226 pollfd &stdoutPipe() {
return pfds[1]; }
227 pollfd &stderrPipe() {
return pfds[2]; }
228 pollfd &forkfd() {
return pfds[3]; }
234QProcessPoller::QProcessPoller(
const QProcessPrivate &proc)
236 for (
int i = 0; i < n_pfds; i++)
237 pfds[i] = qt_make_pollfd(-1, POLLIN);
239 stdoutPipe().fd = proc.stdoutChannel.pipe[0];
240 stderrPipe().fd = proc.stderrChannel.pipe[0];
242 if (!proc.writeBuffer.isEmpty()) {
243 stdinPipe().fd = proc.stdinChannel.pipe[1];
244 stdinPipe().events = POLLOUT;
247 forkfd().fd = proc.forkfd;
250int QProcessPoller::poll(
const QDeadlineTimer &deadline)
252 return qt_safe_poll(pfds, n_pfds, deadline);
258 struct CharPointerList
260 std::unique_ptr<
char *[]> pointers;
262 CharPointerList(
const QString &argv0,
const QStringList &args);
263 explicit CharPointerList(
const QProcessEnvironmentPrivate *env);
264 operator
char **()
const {
return pointers.get(); }
268 void updatePointers(qsizetype count);
271 const QProcessPrivate *d;
272 CharPointerList argv;
273 CharPointerList envp;
275 int workingDirectory = -2;
276 bool isUsingVfork = usingVfork();
280 return workingDirectory != -1;
283 QChildProcess(QProcessPrivate *d)
284 : d(d), argv(resolveExecutable(d->program), d->arguments),
285 envp(d->environmentPrivate())
289 if (!d->workingDirectory.isEmpty()) {
290 workingDirectory = opendirfd(QFile::encodeName(d->workingDirectory));
291 if (workingDirectory < 0) {
292 d->setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall(
"chdir"));
296 isUsingVfork =
false;
311 disableThreadCancellations();
313 ~QChildProcess()
noexcept(
false)
318 void cleanup()
noexcept(
false)
320 if (workingDirectory >= 0)
321 close(workingDirectory);
322 workingDirectory = -1;
325 restoreThreadCancellations();
328 void maybeBlockSignals()
noexcept
335 sigfillset(&emptyset);
336 pthread_sigmask(SIG_SETMASK, &emptyset, &oldsigset);
340 void restoreSignalMask()
const noexcept
344 pthread_sigmask(SIG_SETMASK, &oldsigset,
nullptr);
347 bool usingVfork()
const noexcept;
349 template <
typename Lambda>
int doFork(Lambda &&childLambda)
353 QT_IGNORE_DEPRECATIONS(pid = vfork();)
358 _exit(childLambda());
362 int startChild(pid_t *pid)
364 int ffdflags = FFD_CLOEXEC | (isUsingVfork ? 0 : FFD_USE_FORK);
365 return ::vforkfd(ffdflags, pid, &QChildProcess::startProcess,
this);
369 Q_NORETURN
void startProcess()
const noexcept;
370 static int startProcess(
void *self)
noexcept
372 static_cast<QChildProcess *>(self)->startProcess();
373 Q_UNREACHABLE_RETURN(-1);
376#if defined(PTHREAD_CANCEL_DISABLE)
377 int oldstate = PTHREAD_CANCEL_DISABLE;
378 void disableThreadCancellations()
noexcept
381 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
383 void restoreThreadCancellations()
noexcept(
false)
386 int oldoldstate = std::exchange(oldstate, PTHREAD_CANCEL_DISABLE);
387 if (oldoldstate != PTHREAD_CANCEL_DISABLE) {
389 pthread_setcancelstate(oldoldstate,
nullptr);
393 void disableThreadCancellations()
noexcept {}
394 void restoreThreadCancellations() {}
397 static QString resolveExecutable(
const QString &program);
400QChildProcess::CharPointerList::CharPointerList(
const QString &program,
const QStringList &args)
402 qsizetype count = 1 + args.size();
403 pointers.reset(
new char *[count + 1]);
404 pointers[count] =
nullptr;
408 pointers[0] =
reinterpret_cast<
char *>(0);
409 data = QFile::encodeName(program);
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);
420 updatePointers(count);
423QChildProcess::CharPointerList::CharPointerList(
const QProcessEnvironmentPrivate *environment)
428 QProcessEnvironmentPrivate::MutexLocker locker(environment);
430 const QProcessEnvironmentPrivate::Map &env = environment->vars;
431 qsizetype count = env.size();
432 pointers.reset(
new char *[count + 1]);
433 pointers[count] =
nullptr;
435 const auto end = env.end();
436 auto it = env.begin();
437 for (qsizetype i = 0; it != end; ++it, ++i) {
440 pointers[i] =
reinterpret_cast<
char *>(data.size());
448 updatePointers(count);
451void QChildProcess::CharPointerList::updatePointers(qsizetype count)
453 char *
const base =
const_cast<
char *>(data.constBegin());
454 for (qsizetype i = 0; i < count; ++i)
455 pointers[i] = base + qptrdiff(pointers[i]);
459static bool qt_pollfd_check(
const pollfd &pfd,
short revents)
461 return pfd.fd >= 0 && (pfd.revents & (revents | POLLHUP | POLLERR | POLLNVAL)) != 0;
464static int qt_create_pipe(
int *pipe)
467 qt_safe_close(pipe[0]);
469 qt_safe_close(pipe[1]);
470 int pipe_ret = qt_safe_pipe(pipe);
472 QScopedValueRollback rollback(errno);
473 qErrnoWarning(
"QProcess: Cannot create pipe");
478void QProcessPrivate::destroyPipe(
int *pipe)
481 qt_safe_close(pipe[1]);
485 qt_safe_close(pipe[0]);
490void QProcessPrivate::closeChannel(Channel *channel)
492 delete channel->notifier;
493 channel->notifier =
nullptr;
495 destroyPipe(channel->pipe);
498void QProcessPrivate::cleanup()
500 q_func()->setProcessState(QProcess::NotRunning);
503 delete stateNotifier;
504 stateNotifier =
nullptr;
505 destroyPipe(childStartedPipe);
508 qt_safe_close(forkfd);
514
515
516bool QProcessPrivate::openChannel(Channel &channel)
520 if (channel.type == Channel::Normal) {
522 if (qt_create_pipe(channel.pipe) != 0) {
523 setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall(
"pipe"));
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);
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,
545 }
else if (channel.type == Channel::Redirect) {
547 QByteArray fname = QFile::encodeName(channel.file);
549 if (&channel == &stdinChannel) {
551 channel.pipe[1] = -1;
552 if ( (channel.pipe[0] = qt_safe_open(fname, O_RDONLY)) != -1)
554 setErrorAndEmit(QProcess::FailedToStart,
555 QProcess::tr(
"Could not open input redirection for reading"));
557 int mode = O_WRONLY | O_CREAT;
563 channel.pipe[0] = -1;
564 if ( (channel.pipe[1] = qt_safe_open(fname, mode, 0666)) != -1)
567 setErrorAndEmit(QProcess::FailedToStart,
568 QProcess::tr(
"Could not open input redirection for reading"));
572 Q_ASSERT_X(channel.process,
"QProcess::start",
"Internal error");
577 if (channel.type == Channel::PipeSource) {
580 sink = &channel.process->stdinChannel;
582 Q_ASSERT(source == &stdoutChannel);
583 Q_ASSERT(sink->process ==
this && sink->type == Channel::PipeSink);
586 source = &channel.process->stdoutChannel;
589 Q_ASSERT(sink == &stdinChannel);
590 Q_ASSERT(source->process ==
this && source->type == Channel::PipeSource);
593 if (source->pipe[1] != INVALID_Q_PIPE || sink->pipe[0] != INVALID_Q_PIPE) {
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);
600 Q_PIPE pipe[2] = { -1, -1 };
601 if (qt_create_pipe(pipe) != 0) {
602 setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall(
"pipe"));
605 sink->pipe[0] = pipe[0];
606 source->pipe[1] = pipe[1];
613void QProcessPrivate::commitChannels()
const
616 if (stdinChannel.pipe[0] != INVALID_Q_PIPE)
617 qt_safe_dup2(stdinChannel.pipe[0], STDIN_FILENO, 0);
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);
626 if (processChannelMode == QProcess::MergedChannels)
627 qt_safe_dup2(STDOUT_FILENO, STDERR_FILENO, 0);
631inline QString QChildProcess::resolveExecutable(
const QString &program)
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);
643 Q_CONSTINIT
static QBasicMutex cfbundleMutex;
644 const auto locker = qt_scoped_lock(cfbundleMutex);
645 QCFType<CFBundleRef> bundle = CFBundleCreate(0, url);
647 QCFType<CFURLRef> executableURL = CFBundleCopyExecutableURL(bundle);
649 url = CFURLCopyAbsoluteURL(executableURL);
652 const QCFString str = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
653 return QString::fromCFString(str);
658 if (!program.contains(u'/')) {
662 return QStandardPaths::findExecutable(program);
668__attribute__((weak)) pid_t __interceptor_vfork();
671inline bool globalUsingVfork()
noexcept
673#if defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer)
677#if defined(__SANITIZE_THREAD__) || __has_feature(thread_sanitizer)
681#if defined(Q_OS_LINUX) && !QT_CONFIG(forkfd_pidfd)
687#if defined(Q_OS_DARWIN)
692#if defined(Q_OS_CYGWIN)
700 return __interceptor_vfork ==
nullptr;
703inline bool QChildProcess::usingVfork()
const noexcept
705 if (!globalUsingVfork())
708 if (!d->unixExtras || !d->unixExtras->childProcessModifier)
713 auto flags = d->unixExtras->processParameters.flags;
714 return flags.testFlag(QProcess::UnixProcessFlag::UseVFork);
717#ifdef QT_BUILD_INTERNAL
718Q_AUTOTEST_EXPORT
bool _qprocessUsingVfork()
noexcept
720 return globalUsingVfork();
724void QProcessPrivate::startProcess()
727 q->setProcessState(QProcess::Starting);
729#if defined (QPROCESS_DEBUG)
730 qDebug(
"QProcessPrivate::startProcess()");
734 if (!openChannels()) {
736 Q_ASSERT(!errorString.isEmpty());
740 if (qt_create_pipe(childStartedPipe) != 0) {
741 setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall(
"pipe"));
746 if (threadData.loadRelaxed()->hasEventDispatcher()) {
750 stateNotifier =
new QSocketNotifier(childStartedPipe[0],
751 QSocketNotifier::Read, q);
752 QObjectPrivate::connect(stateNotifier, &QSocketNotifier::activated,
this,
753 &QProcessPrivate::_q_startupNotification);
757 QChildProcess childProcess(
this);
758 if (!childProcess.ok()) {
759 Q_ASSERT(processError != QProcess::UnknownError);
764 forkfd = childProcess.startChild(&pid);
765 int lastForkErrno = errno;
769 childProcess.cleanup();
770#if defined (QPROCESS_DEBUG)
771 qDebug(
"fork failed: %ls", qUtf16Printable(qt_error_string(lastForkErrno)));
773 q->setProcessState(QProcess::NotRunning);
774 setErrorAndEmit(QProcess::FailedToStart,
775 QProcess::tr(
"Resource error (fork failure): %1").arg(qt_error_string(lastForkErrno)));
784 qt_safe_close(childStartedPipe[1]);
785 childStartedPipe[1] = -1;
787 if (stdinChannel.pipe[0] != -1) {
788 qt_safe_close(stdinChannel.pipe[0]);
789 stdinChannel.pipe[0] = -1;
792 if (stdinChannel.pipe[1] != -1)
793 ::fcntl(stdinChannel.pipe[1], F_SETFL, ::fcntl(stdinChannel.pipe[1], F_GETFL) | O_NONBLOCK);
795 if (stdoutChannel.pipe[1] != -1) {
796 qt_safe_close(stdoutChannel.pipe[1]);
797 stdoutChannel.pipe[1] = -1;
800 if (stdoutChannel.pipe[0] != -1)
801 ::fcntl(stdoutChannel.pipe[0], F_SETFL, ::fcntl(stdoutChannel.pipe[0], F_GETFL) | O_NONBLOCK);
803 if (stderrChannel.pipe[1] != -1) {
804 qt_safe_close(stderrChannel.pipe[1]);
805 stderrChannel.pipe[1] = -1;
807 if (stderrChannel.pipe[0] != -1)
808 ::fcntl(stderrChannel.pipe[0], F_SETFL, ::fcntl(stderrChannel.pipe[0], F_GETFL) | O_NONBLOCK);
812failChildProcess(
const QProcessPrivate *d,
const char *description,
int code)
noexcept
814 ChildError error = {};
816 qstrncpy(error.function, description,
sizeof(error.function));
817 qt_safe_write(d->childStartedPipe[1], &error,
sizeof(error));
821void QProcess::failChildProcessModifier(
const char *description,
int error)
noexcept
824 failChildProcess(d_func(), description, -error);
828static const char *applyProcessParameters(
const QProcess::UnixProcessParameters ¶ms)
832 bool ignore_sigpipe = params.flags.testFlag(QProcess::UnixProcessFlag::IgnoreSigPipe);
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);
846 sigprocmask(SIG_SETMASK, &set,
nullptr);
851 if (params.flags.testFlag(QProcess::UnixProcessFlag::CloseFileDescriptors)) {
853 int fd = qMax(STDERR_FILENO + 1, params.lowestFileDescriptorToClose);
854#ifdef CLOSE_RANGE_CLOEXEC
860 r = close_range(fd, INT_MAX, CLOSE_RANGE_CLOEXEC);
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);
876 if (params.flags.testFlag(QProcess::UnixProcessFlag::CreateNewSession)) {
883 if (params.flags.testFlag(QProcess::UnixProcessFlag::DisconnectControllingTerminal)) {
885 if (
int fd = open(_PATH_TTY, O_RDONLY | O_NOCTTY); fd >= 0) {
887 int r = ioctl(fd, TIOCNOTTY);
888 int savedErrno = errno;
899 if (params.flags.testFlag(QProcess::UnixProcessFlag::DisableCoreDumps)) {
900 if (
struct rlimit lim; getrlimit(RLIMIT_CORE, &lim) == 0 && lim.rlim_cur) {
905 (
void) setrlimit(RLIMIT_CORE, &lim);
912 if (params.flags.testFlag(QProcess::UnixProcessFlag::ResetIds)) {
913 int r = setgid(getgid());
914 r = setuid(getuid());
922static void callChildProcessModifier(
const QProcessPrivate *d)
noexcept
925 if (d->unixExtras->childProcessModifier)
926 d->unixExtras->childProcessModifier();
927 } QT_CATCH (std::exception &e) {
928 failChildProcess(d, e.what(), FakeErrnoForThrow);
930 failChildProcess(d,
"throw", FakeErrnoForThrow);
939void QChildProcess::startProcess()
const noexcept
945 qt_safe_close(d->childStartedPipe[0]);
948 if (workingDirectory >= 0 && fchdir(workingDirectory) == -1)
949 failChildProcess(d,
"fchdir", errno);
951 bool sigpipeHandled =
false;
952 bool sigmaskHandled =
false;
956 callChildProcessModifier(d);
959 if (
const char *what = applyProcessParameters(d->unixExtras->processParameters))
960 failChildProcess(d, what, errno);
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);
967 if (!sigpipeHandled) {
969 QtVforkSafe::change_sigpipe(SIG_DFL);
971 if (!sigmaskHandled) {
979 qt_safe_execv(argv[0], argv);
981 qt_safe_execve(argv[0], argv, envp);
982 failChildProcess(d,
"execve", errno);
985bool QProcessPrivate::processStarted(QString *errorMessage)
990 ssize_t ret = qt_safe_read(childStartedPipe[0], &buf,
sizeof(buf));
993 stateNotifier->setEnabled(
false);
994 stateNotifier->disconnect(q);
996 qt_safe_close(childStartedPipe[0]);
997 childStartedPipe[0] = -1;
999#if defined (QPROCESS_DEBUG)
1000 qDebug(
"QProcessPrivate::processStarted() == %s", ret <= 0 ?
"true" :
"false");
1004 if (stateNotifier) {
1005 QObjectPrivate::connect(stateNotifier, &QSocketNotifier::activated,
this,
1006 &QProcessPrivate::_q_processDied);
1007 stateNotifier->setSocket(forkfd);
1008 stateNotifier->setEnabled(
true);
1010 if (stdoutChannel.notifier)
1011 stdoutChannel.notifier->setEnabled(
true);
1012 if (stderrChannel.notifier)
1013 stderrChannel.notifier->setEnabled(
true);
1020 *errorMessage = startFailureErrorMessage(buf, ret);
1025qint64 QProcessPrivate::bytesAvailableInChannel(
const Channel *channel)
const
1027 Q_ASSERT(channel->pipe[0] != INVALID_Q_PIPE);
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);
1038qint64 QProcessPrivate::readFromChannel(
const Channel *channel,
char *data, qint64 maxlen)
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);
1049 if (bytesRead == -1 && errno == EWOULDBLOCK)
1055
1056qint64 QProcess::writeData(
const char *data, qint64 len)
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);
1068 d->write(data, len);
1069 if (d->stdinChannel.notifier)
1070 d->stdinChannel.notifier->setEnabled(
true);
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);
1079bool QProcessPrivate::_q_canWrite()
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).");
1090 const bool writeSucceeded = writeToStdin();
1092 if (writeBuffer.isEmpty() && stdinChannel.closed)
1093 closeWriteChannel();
1094 else if (stdinChannel.notifier)
1095 stdinChannel.notifier->setEnabled(!writeBuffer.isEmpty());
1097 return writeSucceeded;
1100bool QProcessPrivate::writeToStdin()
1102 const char *data = writeBuffer.readPointer();
1103 const qint64 bytesToWrite = writeBuffer.nextDataBlockSize();
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);
1110 qDebug(
"QProcessPrivate::writeToStdin(), failed to write (%ls)", qUtf16Printable(qt_error_string(errno)));
1112 if (written == -1) {
1116 if (errno == EAGAIN)
1119 closeChannel(&stdinChannel);
1120 setErrorAndEmit(QProcess::WriteError);
1123 writeBuffer.free(written);
1124 if (!emittedBytesWritten && written != 0) {
1125 emittedBytesWritten =
true;
1126 emit q_func()->bytesWritten(written);
1127 emittedBytesWritten =
false;
1132void QProcessPrivate::terminateProcess()
1134#if defined (QPROCESS_DEBUG)
1135 qDebug(
"QProcessPrivate::terminateProcess() pid=%jd", intmax_t(pid));
1138 ::kill(pid, SIGTERM);
1141void QProcessPrivate::killProcess()
1143#if defined (QPROCESS_DEBUG)
1144 qDebug(
"QProcessPrivate::killProcess() pid=%jd", intmax_t(pid));
1147 ::kill(pid, SIGKILL);
1150bool QProcessPrivate::waitForStarted(
const QDeadlineTimer &deadline)
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]);
1158 pollfd pfd = qt_make_pollfd(childStartedPipe[0], POLLIN);
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);
1168 bool startedEmitted = _q_startupNotification();
1169#if defined (QPROCESS_DEBUG)
1170 qDebug(
"QProcessPrivate::waitForStarted() == %s", startedEmitted ?
"true" :
"false");
1172 return startedEmitted;
1175bool QProcessPrivate::waitForReadyRead(
const QDeadlineTimer &deadline)
1177#if defined (QPROCESS_DEBUG)
1178 qDebug(
"QProcessPrivate::waitForReadyRead(%lld)", deadline.remainingTime());
1182 QProcessPoller poller(*
this);
1184 int ret = poller.poll(deadline);
1190 setError(QProcess::Timedout);
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;
1202 if (readyReadEmitted)
1205 if (qt_pollfd_check(poller.stdinPipe(), POLLOUT))
1209 if (processState == QProcess::NotRunning)
1214 if (qt_pollfd_check(poller.forkfd(), POLLIN)) {
1222bool QProcessPrivate::waitForBytesWritten(
const QDeadlineTimer &deadline)
1224#if defined (QPROCESS_DEBUG)
1225 qDebug(
"QProcessPrivate::waitForBytesWritten(%lld)", deadline.remainingTime());
1228 while (!writeBuffer.isEmpty()) {
1229 QProcessPoller poller(*
this);
1231 int ret = poller.poll(deadline);
1238 setError(QProcess::Timedout);
1242 if (qt_pollfd_check(poller.stdinPipe(), POLLOUT))
1243 return _q_canWrite();
1245 if (qt_pollfd_check(poller.stdoutPipe(), POLLIN))
1246 _q_canReadStandardOutput();
1248 if (qt_pollfd_check(poller.stderrPipe(), POLLIN))
1249 _q_canReadStandardError();
1252 if (processState == QProcess::NotRunning)
1255 if (qt_pollfd_check(poller.forkfd(), POLLIN)) {
1264bool QProcessPrivate::waitForFinished(
const QDeadlineTimer &deadline)
1266#if defined (QPROCESS_DEBUG)
1267 qDebug(
"QProcessPrivate::waitForFinished(%lld)", deadline.remainingTime());
1271 QProcessPoller poller(*
this);
1273 int ret = poller.poll(deadline);
1279 setError(QProcess::Timedout);
1283 if (qt_pollfd_check(poller.stdinPipe(), POLLOUT))
1286 if (qt_pollfd_check(poller.stdoutPipe(), POLLIN))
1287 _q_canReadStandardOutput();
1289 if (qt_pollfd_check(poller.stderrPipe(), POLLIN))
1290 _q_canReadStandardError();
1293 if (processState == QProcess::NotRunning)
1296 if (qt_pollfd_check(poller.forkfd(), POLLIN)) {
1304void QProcessPrivate::waitForDeadChild()
1306 Q_ASSERT(forkfd != -1);
1309 forkfd_info info = {};
1312 QT_EINTR_LOOP(ret, forkfd_wait(forkfd, &info,
nullptr));
1314 exitCode = info.status;
1315 exitStatus = info.code == CLD_EXITED ? QProcess::NormalExit : QProcess::CrashExit;
1317 delete stateNotifier;
1318 stateNotifier =
nullptr;
1320 QT_EINTR_LOOP(ret, forkfd_close(forkfd));
1323#if defined QPROCESS_DEBUG
1324 qDebug() <<
"QProcessPrivate::waitForDeadChild() dead with exitCode"
1325 << exitCode <<
", crashed?" << (info.code != CLD_EXITED);
1329bool QProcessPrivate::startDetached(qint64 *pid)
1331 AutoPipe startedPipe, pidPipe;
1332 if (!startedPipe || !pidPipe) {
1333 setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall(
"pipe"));
1337 if (!openChannelsForDetached()) {
1344 QChildProcess childProcess(
this);
1345 if (!childProcess.ok()) {
1346 Q_ASSERT(processError != QProcess::UnknownError);
1350 childStartedPipe[1] = startedPipe[1];
1351 pid_t childPid = childProcess.doFork([&] {
1354 qt_safe_close(startedPipe[0]);
1355 qt_safe_close(pidPipe[0]);
1357 pid_t doubleForkPid;
1358 if (childProcess.startChild(&doubleForkPid) == -1)
1359 failChildProcess(
this,
"fork", errno);
1362 qt_safe_write(pidPipe[1], &doubleForkPid,
sizeof(pid_t));
1365 childStartedPipe[1] = -1;
1367 int savedErrno = errno;
1370 if (childPid == -1) {
1371 childProcess.cleanup();
1372 setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall(
"fork", savedErrno));
1377 qt_safe_close(pidPipe[1]);
1378 qt_safe_close(startedPipe[1]);
1379 pidPipe[1] = startedPipe[1] = -1;
1386 ChildError childStatus;
1387 ssize_t startResult = qt_safe_read(startedPipe[0], &childStatus,
sizeof(childStatus));
1391 qt_safe_waitpid(childPid, &result, 0);
1393 bool success = (startResult == 0);
1394 if (success && pid) {
1396 if (qt_safe_read(pidPipe[0], &actualPid,
sizeof(pid_t)) !=
sizeof(pid_t))
1399 }
else if (!success) {
1402 childProcess.cleanup();
1403 setErrorAndEmit(QProcess::FailedToStart,
1404 startFailureErrorMessage(childStatus, startResult));