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"
70# undef PTHREAD_CANCEL_DISABLE
75using namespace Qt::StringLiterals;
77#if !defined(Q_OS_DARWIN)
79QProcessEnvironment QProcessEnvironment::systemEnvironment()
81 QProcessEnvironment env;
83 for (
int count = 0; (entry = environ[count]); ++count) {
84 const char *equal = strchr(entry,
'=');
88 QByteArray name(entry, equal - entry);
89 QByteArray value(equal + 1);
90 env.d->vars.insert(QProcessEnvironmentPrivate::Key(name),
91 QProcessEnvironmentPrivate::Value(value));
100namespace QtVforkSafe {
125#if defined(Q_OS_FREEBSD)
127# define 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));
137# define DECLARE_FUNCTIONS(NAME) using ::NAME;
141DECLARE_FUNCTIONS(sigaction)
145#undef DECLARE_FUNCTIONS
148static void change_sigpipe(
decltype(SIG_DFL) new_handler)
151 memset(&sa, 0,
sizeof(sa));
152 sa.sa_handler = new_handler;
153 sigaction(SIGPIPE, &sa,
nullptr);
157static int opendirfd(QByteArray encodedName)
162 if (encodedName !=
"/" && !encodedName.endsWith(
"/."))
164 return qt_safe_open(encodedName, QT_OPEN_RDONLY | O_DIRECTORY | O_PATH);
170 int pipe[2] = { -1, -1 };
171 AutoPipe(
int flags = 0)
173 qt_safe_pipe(pipe, flags);
177 for (
int fd : pipe) {
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]; }
191 char function[_POSIX_PIPE_BUF -
sizeof(code)];
193static_assert(std::is_trivially_copy_constructible_v<ChildError>);
195static_assert(PIPE_BUF >=
sizeof(ChildError));
200static constexpr int FakeErrnoForThrow = std::numeric_limits<
int>::max();
202static QString errorMessageForSyscall(QUtf8StringView fnName,
int errnoCode = -1)
204 QString msg = qt_error_string(errnoCode);
205 return QProcess::tr(
"Child process set up failed: %1: %2").arg(fnName, msg);
208static QString startFailureErrorMessage(ChildError &err, [[maybe_unused]] ssize_t bytesRead)
212 Q_ASSERT(bytesRead ==
sizeof(err));
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")
220 return QProcess::tr(
"Child process modifier reported error: %1")
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);
230 QProcessPoller(
const QProcessPrivate &proc);
232 int poll(
const QDeadlineTimer &deadline);
234 pollfd &stdinPipe() {
return pfds[0]; }
235 pollfd &stdoutPipe() {
return pfds[1]; }
236 pollfd &stderrPipe() {
return pfds[2]; }
237 pollfd &forkfd() {
return pfds[3]; }
243QProcessPoller::QProcessPoller(
const QProcessPrivate &proc)
245 for (
int i = 0; i < n_pfds; i++)
246 pfds[i] = qt_make_pollfd(-1, POLLIN);
248 stdoutPipe().fd = proc.stdoutChannel.pipe[0];
249 stderrPipe().fd = proc.stderrChannel.pipe[0];
251 if (!proc.writeBuffer.isEmpty()) {
252 stdinPipe().fd = proc.stdinChannel.pipe[1];
253 stdinPipe().events = POLLOUT;
256 forkfd().fd = proc.forkfd;
259int QProcessPoller::poll(
const QDeadlineTimer &deadline)
261 return qt_safe_poll(pfds, n_pfds, deadline);
267 struct CharPointerList
269 std::unique_ptr<
char *[]> pointers;
271 CharPointerList(
const QString &argv0,
const QStringList &args);
272 explicit CharPointerList(
const QProcessEnvironmentPrivate *env);
273 operator
char **()
const {
return pointers.get(); }
277 void updatePointers(qsizetype count);
280 const QProcessPrivate *d;
281 CharPointerList argv;
282 CharPointerList envp;
284 int workingDirectory = -2;
285 bool isUsingVfork = usingVfork();
289 return workingDirectory != -1;
292 QChildProcess(QProcessPrivate *d)
293 : d(d), argv(resolveExecutable(d->program), d->arguments),
294 envp(d->environmentPrivate())
298 if (!d->workingDirectory.isEmpty()) {
299 workingDirectory = opendirfd(QFile::encodeName(d->workingDirectory));
300 if (workingDirectory < 0) {
301 d->setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall(
"chdir"));
305 isUsingVfork =
false;
320 disableThreadCancellations();
322 ~QChildProcess()
noexcept(
false)
327 void cleanup()
noexcept(
false)
329 if (workingDirectory >= 0)
330 close(workingDirectory);
331 workingDirectory = -1;
334 restoreThreadCancellations();
337 void maybeBlockSignals()
noexcept
344 sigfillset(&emptyset);
345 pthread_sigmask(SIG_SETMASK, &emptyset, &oldsigset);
349 void restoreSignalMask()
const noexcept
353 pthread_sigmask(SIG_SETMASK, &oldsigset,
nullptr);
356 bool usingVfork()
const noexcept;
358 template <
typename Lambda>
int doFork(Lambda &&childLambda)
362 QT_IGNORE_DEPRECATIONS(pid = vfork();)
367 _exit(childLambda());
371 int startChild(pid_t *pid)
373 int ffdflags = FFD_CLOEXEC | (isUsingVfork ? 0 : FFD_USE_FORK);
374 return ::vforkfd(ffdflags, pid, &QChildProcess::startProcess,
this);
378 Q_NORETURN
void startProcess()
const noexcept;
379 static int startProcess(
void *self)
noexcept
381 static_cast<QChildProcess *>(self)->startProcess();
382 Q_UNREACHABLE_RETURN(-1);
385#if defined(PTHREAD_CANCEL_DISABLE)
386 int oldstate = PTHREAD_CANCEL_DISABLE;
387 void disableThreadCancellations()
noexcept
390 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
392 void restoreThreadCancellations()
noexcept(
false)
395 int oldoldstate = std::exchange(oldstate, PTHREAD_CANCEL_DISABLE);
396 if (oldoldstate != PTHREAD_CANCEL_DISABLE) {
398 pthread_setcancelstate(oldoldstate,
nullptr);
402 void disableThreadCancellations()
noexcept {}
403 void restoreThreadCancellations() {}
406 static QString resolveExecutable(
const QString &program);
409QChildProcess::CharPointerList::CharPointerList(
const QString &program,
const QStringList &args)
411 qsizetype count = 1 + args.size();
412 pointers.reset(
new char *[count + 1]);
413 pointers[count] =
nullptr;
417 pointers[0] =
reinterpret_cast<
char *>(0);
418 data = QFile::encodeName(program);
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);
429 updatePointers(count);
432QChildProcess::CharPointerList::CharPointerList(
const QProcessEnvironmentPrivate *environment)
437 QProcessEnvironmentPrivate::MutexLocker locker(environment);
439 const QProcessEnvironmentPrivate::Map &env = environment->vars;
440 qsizetype count = env.size();
441 pointers.reset(
new char *[count + 1]);
442 pointers[count] =
nullptr;
444 const auto end = env.end();
445 auto it = env.begin();
446 for (qsizetype i = 0; it != end; ++it, ++i) {
449 pointers[i] =
reinterpret_cast<
char *>(data.size());
457 updatePointers(count);
460void QChildProcess::CharPointerList::updatePointers(qsizetype count)
462 char *
const base =
const_cast<
char *>(data.constBegin());
463 for (qsizetype i = 0; i < count; ++i)
464 pointers[i] = base + qptrdiff(pointers[i]);
468static bool qt_pollfd_check(
const pollfd &pfd,
short revents)
470 return pfd.fd >= 0 && (pfd.revents & (revents | POLLHUP | POLLERR | POLLNVAL)) != 0;
473static int qt_create_pipe(
int *pipe)
476 qt_safe_close(pipe[0]);
478 qt_safe_close(pipe[1]);
479 int pipe_ret = qt_safe_pipe(pipe);
481 QScopedValueRollback rollback(errno);
482 qErrnoWarning(
"QProcess: Cannot create pipe");
487void QProcessPrivate::destroyPipe(
int *pipe)
490 qt_safe_close(pipe[1]);
494 qt_safe_close(pipe[0]);
499void QProcessPrivate::closeChannel(Channel *channel)
501 delete channel->notifier;
502 channel->notifier =
nullptr;
504 destroyPipe(channel->pipe);
507void QProcessPrivate::cleanup()
509 q_func()->setProcessState(QProcess::NotRunning);
512 delete stateNotifier;
513 stateNotifier =
nullptr;
514 destroyPipe(childStartedPipe);
517 qt_safe_close(forkfd);
523
524
525bool QProcessPrivate::openChannel(Channel &channel)
529 if (channel.type == Channel::Normal) {
531 if (qt_create_pipe(channel.pipe) != 0) {
532 setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall(
"pipe"));
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);
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,
554 }
else if (channel.type == Channel::Redirect) {
556 QByteArray fname = QFile::encodeName(channel.file);
558 if (&channel == &stdinChannel) {
560 channel.pipe[1] = -1;
561 if ( (channel.pipe[0] = qt_safe_open(fname, O_RDONLY)) != -1)
563 setErrorAndEmit(QProcess::FailedToStart,
564 QProcess::tr(
"Could not open input redirection for reading"));
566 int mode = O_WRONLY | O_CREAT;
572 channel.pipe[0] = -1;
573 if ( (channel.pipe[1] = qt_safe_open(fname, mode, 0666)) != -1)
576 setErrorAndEmit(QProcess::FailedToStart,
577 QProcess::tr(
"Could not open input redirection for reading"));
581 Q_ASSERT_X(channel.process,
"QProcess::start",
"Internal error");
586 if (channel.type == Channel::PipeSource) {
589 sink = &channel.process->stdinChannel;
591 Q_ASSERT(source == &stdoutChannel);
592 Q_ASSERT(sink->process ==
this && sink->type == Channel::PipeSink);
595 source = &channel.process->stdoutChannel;
598 Q_ASSERT(sink == &stdinChannel);
599 Q_ASSERT(source->process ==
this && source->type == Channel::PipeSource);
602 if (source->pipe[1] != INVALID_Q_PIPE || sink->pipe[0] != INVALID_Q_PIPE) {
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);
609 Q_PIPE pipe[2] = { -1, -1 };
610 if (qt_create_pipe(pipe) != 0) {
611 setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall(
"pipe"));
614 sink->pipe[0] = pipe[0];
615 source->pipe[1] = pipe[1];
622void QProcessPrivate::commitChannels()
const
625 if (stdinChannel.pipe[0] != INVALID_Q_PIPE)
626 qt_safe_dup2(stdinChannel.pipe[0], STDIN_FILENO, 0);
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);
635 if (processChannelMode == QProcess::MergedChannels)
636 qt_safe_dup2(STDOUT_FILENO, STDERR_FILENO, 0);
640inline QString QChildProcess::resolveExecutable(
const QString &program)
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);
652 Q_CONSTINIT
static QBasicMutex cfbundleMutex;
653 const auto locker = qt_scoped_lock(cfbundleMutex);
654 QCFType<CFBundleRef> bundle = CFBundleCreate(0, url);
656 QCFType<CFURLRef> executableURL = CFBundleCopyExecutableURL(bundle);
658 url = CFURLCopyAbsoluteURL(executableURL);
661 const QCFString str = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
662 return QString::fromCFString(str);
667 if (!program.contains(u'/')) {
671 return QStandardPaths::findExecutable(program);
677__attribute__((weak)) pid_t __interceptor_vfork();
680inline bool globalUsingVfork()
noexcept
682#if defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer)
686#if defined(__SANITIZE_THREAD__) || __has_feature(thread_sanitizer)
690#if defined(Q_OS_LINUX) && !QT_CONFIG(forkfd_pidfd)
696#if defined(Q_OS_DARWIN)
701#if defined(Q_OS_CYGWIN)
714 return __interceptor_vfork ==
nullptr;
717inline bool QChildProcess::usingVfork()
const noexcept
719 if (!globalUsingVfork())
722 if (!d->unixExtras || !d->unixExtras->childProcessModifier)
727 auto flags = d->unixExtras->processParameters.flags;
728 return flags.testFlag(QProcess::UnixProcessFlag::UseVFork);
731#ifdef QT_BUILD_INTERNAL
732Q_AUTOTEST_EXPORT
bool _qprocessUsingVfork()
noexcept
734 return globalUsingVfork();
738void QProcessPrivate::startProcess()
741 q->setProcessState(QProcess::Starting);
743#if defined (QPROCESS_DEBUG)
744 qDebug(
"QProcessPrivate::startProcess()");
748 if (!openChannels()) {
750 Q_ASSERT(!errorString.isEmpty());
754 if (qt_create_pipe(childStartedPipe) != 0) {
755 setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall(
"pipe"));
760 if (threadData.loadRelaxed()->hasEventDispatcher()) {
764 stateNotifier =
new QSocketNotifier(childStartedPipe[0],
765 QSocketNotifier::Read, q);
766 QObjectPrivate::connect(stateNotifier, &QSocketNotifier::activated,
this,
767 &QProcessPrivate::_q_startupNotification);
771 QChildProcess childProcess(
this);
772 if (!childProcess.ok()) {
773 Q_ASSERT(processError != QProcess::UnknownError);
778 forkfd = childProcess.startChild(&pid);
779 int lastForkErrno = errno;
783 childProcess.cleanup();
784#if defined (QPROCESS_DEBUG)
785 qDebug(
"fork failed: %ls", qUtf16Printable(qt_error_string(lastForkErrno)));
787 q->setProcessState(QProcess::NotRunning);
788 setErrorAndEmit(QProcess::FailedToStart,
789 QProcess::tr(
"Resource error (fork failure): %1").arg(qt_error_string(lastForkErrno)));
798 qt_safe_close(childStartedPipe[1]);
799 childStartedPipe[1] = -1;
801 if (stdinChannel.pipe[0] != -1) {
802 qt_safe_close(stdinChannel.pipe[0]);
803 stdinChannel.pipe[0] = -1;
806 if (stdinChannel.pipe[1] != -1)
807 ::fcntl(stdinChannel.pipe[1], F_SETFL, ::fcntl(stdinChannel.pipe[1], F_GETFL) | O_NONBLOCK);
809 if (stdoutChannel.pipe[1] != -1) {
810 qt_safe_close(stdoutChannel.pipe[1]);
811 stdoutChannel.pipe[1] = -1;
814 if (stdoutChannel.pipe[0] != -1)
815 ::fcntl(stdoutChannel.pipe[0], F_SETFL, ::fcntl(stdoutChannel.pipe[0], F_GETFL) | O_NONBLOCK);
817 if (stderrChannel.pipe[1] != -1) {
818 qt_safe_close(stderrChannel.pipe[1]);
819 stderrChannel.pipe[1] = -1;
821 if (stderrChannel.pipe[0] != -1)
822 ::fcntl(stderrChannel.pipe[0], F_SETFL, ::fcntl(stderrChannel.pipe[0], F_GETFL) | O_NONBLOCK);
826failChildProcess(
const QProcessPrivate *d,
const char *description,
int code)
noexcept
828 ChildError error = {};
830 qstrncpy(error.function, description,
sizeof(error.function));
831 qt_safe_write(d->childStartedPipe[1], &error,
sizeof(error));
835void QProcess::failChildProcessModifier(
const char *description,
int error)
noexcept
838 failChildProcess(d_func(), description, -error);
842static const char *applyProcessParameters(
const QProcess::UnixProcessParameters ¶ms)
846 bool ignore_sigpipe = params.flags.testFlag(QProcess::UnixProcessFlag::IgnoreSigPipe);
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);
860 sigprocmask(SIG_SETMASK, &set,
nullptr);
865 if (params.flags.testFlag(QProcess::UnixProcessFlag::CloseFileDescriptors)) {
867 int fd = qMax(STDERR_FILENO + 1, params.lowestFileDescriptorToClose);
868#ifdef CLOSE_RANGE_CLOEXEC
874 r = close_range(fd, INT_MAX, CLOSE_RANGE_CLOEXEC);
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);
890 if (params.flags.testFlag(QProcess::UnixProcessFlag::CreateNewSession)) {
897 if (params.flags.testFlag(QProcess::UnixProcessFlag::DisconnectControllingTerminal)) {
899 if (
int fd = open(_PATH_TTY, O_RDONLY | O_NOCTTY); fd >= 0) {
901 int r = ioctl(fd, TIOCNOTTY);
902 int savedErrno = errno;
913 if (params.flags.testFlag(QProcess::UnixProcessFlag::DisableCoreDumps)) {
914 if (
struct rlimit lim; getrlimit(RLIMIT_CORE, &lim) == 0 && lim.rlim_cur) {
919 (
void) setrlimit(RLIMIT_CORE, &lim);
926 if (params.flags.testFlag(QProcess::UnixProcessFlag::ResetIds)) {
927 int r = setgid(getgid());
928 r = setuid(getuid());
936static void callChildProcessModifier(
const QProcessPrivate *d)
noexcept
939 if (d->unixExtras->childProcessModifier)
940 d->unixExtras->childProcessModifier();
941 } QT_CATCH (std::exception &e) {
942 failChildProcess(d, e.what(), FakeErrnoForThrow);
944 failChildProcess(d,
"throw", FakeErrnoForThrow);
953void QChildProcess::startProcess()
const noexcept
959 qt_safe_close(d->childStartedPipe[0]);
962 if (workingDirectory >= 0 && fchdir(workingDirectory) == -1)
963 failChildProcess(d,
"fchdir", errno);
965 bool sigpipeHandled =
false;
966 bool sigmaskHandled =
false;
970 callChildProcessModifier(d);
973 if (
const char *what = applyProcessParameters(d->unixExtras->processParameters))
974 failChildProcess(d, what, errno);
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);
981 if (!sigpipeHandled) {
983 QtVforkSafe::change_sigpipe(SIG_DFL);
985 if (!sigmaskHandled) {
993 qt_safe_execv(argv[0], argv);
995 qt_safe_execve(argv[0], argv, envp);
996 failChildProcess(d,
"execve", errno);
999bool QProcessPrivate::processStarted(QString *errorMessage)
1004 ssize_t ret = qt_safe_read(childStartedPipe[0], &buf,
sizeof(buf));
1006 if (stateNotifier) {
1007 stateNotifier->setEnabled(
false);
1008 stateNotifier->disconnect(q);
1010 qt_safe_close(childStartedPipe[0]);
1011 childStartedPipe[0] = -1;
1013#if defined (QPROCESS_DEBUG)
1014 qDebug(
"QProcessPrivate::processStarted() == %s", ret <= 0 ?
"true" :
"false");
1018 if (stateNotifier) {
1019 QObjectPrivate::connect(stateNotifier, &QSocketNotifier::activated,
this,
1020 &QProcessPrivate::_q_processDied);
1021 stateNotifier->setSocket(forkfd);
1022 stateNotifier->setEnabled(
true);
1024 if (stdoutChannel.notifier)
1025 stdoutChannel.notifier->setEnabled(
true);
1026 if (stderrChannel.notifier)
1027 stderrChannel.notifier->setEnabled(
true);
1034 *errorMessage = startFailureErrorMessage(buf, ret);
1039qint64 QProcessPrivate::bytesAvailableInChannel(
const Channel *channel)
const
1041 Q_ASSERT(channel->pipe[0] != INVALID_Q_PIPE);
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);
1052qint64 QProcessPrivate::readFromChannel(
const Channel *channel,
char *data, qint64 maxlen)
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);
1063 if (bytesRead == -1 && errno == EWOULDBLOCK)
1069
1070qint64 QProcess::writeData(
const char *data, qint64 len)
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);
1082 d->write(data, len);
1083 if (d->stdinChannel.notifier)
1084 d->stdinChannel.notifier->setEnabled(
true);
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);
1093bool QProcessPrivate::_q_canWrite()
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).");
1104 const bool writeSucceeded = writeToStdin();
1106 if (writeBuffer.isEmpty() && stdinChannel.closed)
1107 closeWriteChannel();
1108 else if (stdinChannel.notifier)
1109 stdinChannel.notifier->setEnabled(!writeBuffer.isEmpty());
1111 return writeSucceeded;
1114bool QProcessPrivate::writeToStdin()
1116 const char *data = writeBuffer.readPointer();
1117 const qint64 bytesToWrite = writeBuffer.nextDataBlockSize();
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);
1124 qDebug(
"QProcessPrivate::writeToStdin(), failed to write (%ls)", qUtf16Printable(qt_error_string(errno)));
1126 if (written == -1) {
1130 if (errno == EAGAIN)
1133 closeChannel(&stdinChannel);
1134 setErrorAndEmit(QProcess::WriteError);
1137 writeBuffer.free(written);
1138 if (!emittedBytesWritten && written != 0) {
1139 emittedBytesWritten =
true;
1140 emit q_func()->bytesWritten(written);
1141 emittedBytesWritten =
false;
1146void QProcessPrivate::terminateProcess()
1148#if defined (QPROCESS_DEBUG)
1149 qDebug(
"QProcessPrivate::terminateProcess() pid=%jd", intmax_t(pid));
1152 ::kill(pid, SIGTERM);
1155void QProcessPrivate::killProcess()
1157#if defined (QPROCESS_DEBUG)
1158 qDebug(
"QProcessPrivate::killProcess() pid=%jd", intmax_t(pid));
1161 ::kill(pid, SIGKILL);
1164bool QProcessPrivate::waitForStarted(
const QDeadlineTimer &deadline)
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]);
1172 pollfd pfd = qt_make_pollfd(childStartedPipe[0], POLLIN);
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);
1182 bool startedEmitted = _q_startupNotification();
1183#if defined (QPROCESS_DEBUG)
1184 qDebug(
"QProcessPrivate::waitForStarted() == %s", startedEmitted ?
"true" :
"false");
1186 return startedEmitted;
1189bool QProcessPrivate::waitForReadyRead(
const QDeadlineTimer &deadline)
1191#if defined (QPROCESS_DEBUG)
1192 qDebug(
"QProcessPrivate::waitForReadyRead(%lld)", deadline.remainingTime());
1196 QProcessPoller poller(*
this);
1198 int ret = poller.poll(deadline);
1204 setError(QProcess::Timedout);
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;
1216 if (readyReadEmitted)
1219 if (qt_pollfd_check(poller.stdinPipe(), POLLOUT))
1223 if (processState == QProcess::NotRunning)
1228 if (qt_pollfd_check(poller.forkfd(), POLLIN)) {
1236bool QProcessPrivate::waitForBytesWritten(
const QDeadlineTimer &deadline)
1238#if defined (QPROCESS_DEBUG)
1239 qDebug(
"QProcessPrivate::waitForBytesWritten(%lld)", deadline.remainingTime());
1242 while (!writeBuffer.isEmpty()) {
1243 QProcessPoller poller(*
this);
1245 int ret = poller.poll(deadline);
1252 setError(QProcess::Timedout);
1256 if (qt_pollfd_check(poller.stdinPipe(), POLLOUT))
1257 return _q_canWrite();
1259 if (qt_pollfd_check(poller.stdoutPipe(), POLLIN))
1260 _q_canReadStandardOutput();
1262 if (qt_pollfd_check(poller.stderrPipe(), POLLIN))
1263 _q_canReadStandardError();
1266 if (processState == QProcess::NotRunning)
1269 if (qt_pollfd_check(poller.forkfd(), POLLIN)) {
1278bool QProcessPrivate::waitForFinished(
const QDeadlineTimer &deadline)
1280#if defined (QPROCESS_DEBUG)
1281 qDebug(
"QProcessPrivate::waitForFinished(%lld)", deadline.remainingTime());
1285 QProcessPoller poller(*
this);
1287 int ret = poller.poll(deadline);
1293 setError(QProcess::Timedout);
1297 if (qt_pollfd_check(poller.stdinPipe(), POLLOUT))
1300 if (qt_pollfd_check(poller.stdoutPipe(), POLLIN))
1301 _q_canReadStandardOutput();
1303 if (qt_pollfd_check(poller.stderrPipe(), POLLIN))
1304 _q_canReadStandardError();
1307 if (processState == QProcess::NotRunning)
1310 if (qt_pollfd_check(poller.forkfd(), POLLIN)) {
1318void QProcessPrivate::waitForDeadChild()
1320 Q_ASSERT(forkfd != -1);
1323 forkfd_info info = {};
1326 QT_EINTR_LOOP(ret, forkfd_wait(forkfd, &info,
nullptr));
1328 exitCode = info.status;
1329 exitStatus = info.code == CLD_EXITED ? QProcess::NormalExit : QProcess::CrashExit;
1331 delete stateNotifier;
1332 stateNotifier =
nullptr;
1334 QT_EINTR_LOOP(ret, forkfd_close(forkfd));
1337#if defined QPROCESS_DEBUG
1338 qDebug() <<
"QProcessPrivate::waitForDeadChild() dead with exitCode"
1339 << exitCode <<
", crashed?" << (info.code != CLD_EXITED);
1343bool QProcessPrivate::startDetached(qint64 *pid)
1345 AutoPipe startedPipe, pidPipe;
1346 if (!startedPipe || !pidPipe) {
1347 setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall(
"pipe"));
1351 if (!openChannelsForDetached()) {
1358 QChildProcess childProcess(
this);
1359 if (!childProcess.ok()) {
1360 Q_ASSERT(processError != QProcess::UnknownError);
1364 childStartedPipe[1] = startedPipe[1];
1365 pid_t childPid = childProcess.doFork([&] {
1368 qt_safe_close(startedPipe[0]);
1369 qt_safe_close(pidPipe[0]);
1371 pid_t doubleForkPid;
1372 if (childProcess.startChild(&doubleForkPid) == -1)
1373 failChildProcess(
this,
"fork", errno);
1376 qt_safe_write(pidPipe[1], &doubleForkPid,
sizeof(pid_t));
1379 childStartedPipe[1] = -1;
1381 int savedErrno = errno;
1384 if (childPid == -1) {
1385 childProcess.cleanup();
1386 setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall(
"fork", savedErrno));
1391 qt_safe_close(pidPipe[1]);
1392 qt_safe_close(startedPipe[1]);
1393 pidPipe[1] = startedPipe[1] = -1;
1400 ChildError childStatus;
1401 ssize_t startResult = qt_safe_read(startedPipe[0], &childStatus,
sizeof(childStatus));
1405 qt_safe_waitpid(childPid, &result, 0);
1407 bool success = (startResult == 0);
1408 if (success && pid) {
1410 if (qt_safe_read(pidPipe[0], &actualPid,
sizeof(pid_t)) !=
sizeof(pid_t))
1413 }
else if (!success) {
1416 childProcess.cleanup();
1417 setErrorAndEmit(QProcess::FailedToStart,
1418 startFailureErrorMessage(childStatus, startResult));