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 const QProcessEnvironmentPrivate::Map &env = environment->vars;
429 qsizetype count = env.size();
430 pointers.reset(
new char *[count + 1]);
431 pointers[count] =
nullptr;
433 const auto end = env.end();
434 auto it = env.begin();
435 for (qsizetype i = 0; it != end; ++it, ++i) {
438 pointers[i] =
reinterpret_cast<
char *>(data.size());
446 updatePointers(count);
449void QChildProcess::CharPointerList::updatePointers(qsizetype count)
451 char *
const base =
const_cast<
char *>(data.constBegin());
452 for (qsizetype i = 0; i < count; ++i)
453 pointers[i] = base + qptrdiff(pointers[i]);
457static bool qt_pollfd_check(
const pollfd &pfd,
short revents)
459 return pfd.fd >= 0 && (pfd.revents & (revents | POLLHUP | POLLERR | POLLNVAL)) != 0;
462static int qt_create_pipe(
int *pipe)
465 qt_safe_close(pipe[0]);
467 qt_safe_close(pipe[1]);
468 int pipe_ret = qt_safe_pipe(pipe);
470 QScopedValueRollback rollback(errno);
471 qErrnoWarning(
"QProcess: Cannot create pipe");
476void QProcessPrivate::destroyPipe(
int *pipe)
479 qt_safe_close(pipe[1]);
483 qt_safe_close(pipe[0]);
488void QProcessPrivate::closeChannel(Channel *channel)
490 delete channel->notifier;
491 channel->notifier =
nullptr;
493 destroyPipe(channel->pipe);
496void QProcessPrivate::cleanup()
498 q_func()->setProcessState(QProcess::NotRunning);
501 delete stateNotifier;
502 stateNotifier =
nullptr;
503 destroyPipe(childStartedPipe);
506 qt_safe_close(forkfd);
512
513
514bool QProcessPrivate::openChannel(Channel &channel)
518 if (channel.type == Channel::Normal) {
520 if (qt_create_pipe(channel.pipe) != 0) {
521 setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall(
"pipe"));
526 if (threadData.loadRelaxed()->hasEventDispatcher()) {
527 if (&channel == &stdinChannel) {
528 channel.notifier =
new QSocketNotifier(QSocketNotifier::Write, q);
529 channel.notifier->setSocket(channel.pipe[1]);
530 QObjectPrivate::connect(channel.notifier, &QSocketNotifier::activated,
this,
531 &QProcessPrivate::_q_canWrite);
533 channel.notifier =
new QSocketNotifier(QSocketNotifier::Read, q);
534 channel.notifier->setSocket(channel.pipe[0]);
535 auto receiver = &channel == &stdoutChannel ? &QProcessPrivate::_q_canReadStandardOutput
536 : &QProcessPrivate::_q_canReadStandardError;
537 QObjectPrivate::connect(channel.notifier, &QSocketNotifier::activated,
this,
543 }
else if (channel.type == Channel::Redirect) {
545 QByteArray fname = QFile::encodeName(channel.file);
547 if (&channel == &stdinChannel) {
549 channel.pipe[1] = -1;
550 if ( (channel.pipe[0] = qt_safe_open(fname, O_RDONLY)) != -1)
552 setErrorAndEmit(QProcess::FailedToStart,
553 QProcess::tr(
"Could not open input redirection for reading"));
555 int mode = O_WRONLY | O_CREAT;
561 channel.pipe[0] = -1;
562 if ( (channel.pipe[1] = qt_safe_open(fname, mode, 0666)) != -1)
565 setErrorAndEmit(QProcess::FailedToStart,
566 QProcess::tr(
"Could not open input redirection for reading"));
570 Q_ASSERT_X(channel.process,
"QProcess::start",
"Internal error");
575 if (channel.type == Channel::PipeSource) {
578 sink = &channel.process->stdinChannel;
580 Q_ASSERT(source == &stdoutChannel);
581 Q_ASSERT(sink->process ==
this && sink->type == Channel::PipeSink);
584 source = &channel.process->stdoutChannel;
587 Q_ASSERT(sink == &stdinChannel);
588 Q_ASSERT(source->process ==
this && source->type == Channel::PipeSource);
591 if (source->pipe[1] != INVALID_Q_PIPE || sink->pipe[0] != INVALID_Q_PIPE) {
595 Q_ASSERT(source->pipe[0] == INVALID_Q_PIPE && source->pipe[1] == INVALID_Q_PIPE);
596 Q_ASSERT(sink->pipe[0] == INVALID_Q_PIPE && sink->pipe[1] == INVALID_Q_PIPE);
598 Q_PIPE pipe[2] = { -1, -1 };
599 if (qt_create_pipe(pipe) != 0) {
600 setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall(
"pipe"));
603 sink->pipe[0] = pipe[0];
604 source->pipe[1] = pipe[1];
611void QProcessPrivate::commitChannels()
const
614 if (stdinChannel.pipe[0] != INVALID_Q_PIPE)
615 qt_safe_dup2(stdinChannel.pipe[0], STDIN_FILENO, 0);
618 if (stdoutChannel.pipe[1] != INVALID_Q_PIPE)
619 qt_safe_dup2(stdoutChannel.pipe[1], STDOUT_FILENO, 0);
620 if (stderrChannel.pipe[1] != INVALID_Q_PIPE) {
621 qt_safe_dup2(stderrChannel.pipe[1], STDERR_FILENO, 0);
624 if (processChannelMode == QProcess::MergedChannels)
625 qt_safe_dup2(STDOUT_FILENO, STDERR_FILENO, 0);
629inline QString QChildProcess::resolveExecutable(
const QString &program)
633 QFileInfo fileInfo(program);
634 if (program.endsWith(
".app"_L1) && fileInfo.isDir()) {
635 QCFType<CFURLRef> url = CFURLCreateWithFileSystemPath(0,
636 QCFString(fileInfo.absoluteFilePath()),
637 kCFURLPOSIXPathStyle,
true);
641 Q_CONSTINIT
static QBasicMutex cfbundleMutex;
642 const auto locker = qt_scoped_lock(cfbundleMutex);
643 QCFType<CFBundleRef> bundle = CFBundleCreate(0, url);
645 QCFType<CFURLRef> executableURL = CFBundleCopyExecutableURL(bundle);
647 url = CFURLCopyAbsoluteURL(executableURL);
650 const QCFString str = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
651 return QString::fromCFString(str);
656 if (!program.contains(u'/')) {
660 return QStandardPaths::findExecutable(program);
666__attribute__((weak)) pid_t __interceptor_vfork();
669inline bool globalUsingVfork()
noexcept
671#if defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer)
675#if defined(__SANITIZE_THREAD__) || __has_feature(thread_sanitizer)
679#if defined(Q_OS_LINUX) && !QT_CONFIG(forkfd_pidfd)
685#if defined(Q_OS_DARWIN)
690#if defined(Q_OS_CYGWIN)
698 return __interceptor_vfork ==
nullptr;
701inline bool QChildProcess::usingVfork()
const noexcept
703 if (!globalUsingVfork())
706 if (!d->unixExtras || !d->unixExtras->childProcessModifier)
711 auto flags = d->unixExtras->processParameters.flags;
712 return flags.testFlag(QProcess::UnixProcessFlag::UseVFork);
715#ifdef QT_BUILD_INTERNAL
716Q_AUTOTEST_EXPORT
bool _qprocessUsingVfork()
noexcept
718 return globalUsingVfork();
722void QProcessPrivate::startProcess()
725 q->setProcessState(QProcess::Starting);
727#if defined (QPROCESS_DEBUG)
728 qDebug(
"QProcessPrivate::startProcess()");
732 if (!openChannels()) {
734 Q_ASSERT(!errorString.isEmpty());
738 if (qt_create_pipe(childStartedPipe) != 0) {
739 setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall(
"pipe"));
744 if (threadData.loadRelaxed()->hasEventDispatcher()) {
748 stateNotifier =
new QSocketNotifier(childStartedPipe[0],
749 QSocketNotifier::Read, q);
750 QObjectPrivate::connect(stateNotifier, &QSocketNotifier::activated,
this,
751 &QProcessPrivate::_q_startupNotification);
755 QChildProcess childProcess(
this);
756 if (!childProcess.ok()) {
757 Q_ASSERT(processError != QProcess::UnknownError);
762 forkfd = childProcess.startChild(&pid);
763 int lastForkErrno = errno;
767 childProcess.cleanup();
768#if defined (QPROCESS_DEBUG)
769 qDebug(
"fork failed: %ls", qUtf16Printable(qt_error_string(lastForkErrno)));
771 q->setProcessState(QProcess::NotRunning);
772 setErrorAndEmit(QProcess::FailedToStart,
773 QProcess::tr(
"Resource error (fork failure): %1").arg(qt_error_string(lastForkErrno)));
782 qt_safe_close(childStartedPipe[1]);
783 childStartedPipe[1] = -1;
785 if (stdinChannel.pipe[0] != -1) {
786 qt_safe_close(stdinChannel.pipe[0]);
787 stdinChannel.pipe[0] = -1;
790 if (stdinChannel.pipe[1] != -1)
791 ::fcntl(stdinChannel.pipe[1], F_SETFL, ::fcntl(stdinChannel.pipe[1], F_GETFL) | O_NONBLOCK);
793 if (stdoutChannel.pipe[1] != -1) {
794 qt_safe_close(stdoutChannel.pipe[1]);
795 stdoutChannel.pipe[1] = -1;
798 if (stdoutChannel.pipe[0] != -1)
799 ::fcntl(stdoutChannel.pipe[0], F_SETFL, ::fcntl(stdoutChannel.pipe[0], F_GETFL) | O_NONBLOCK);
801 if (stderrChannel.pipe[1] != -1) {
802 qt_safe_close(stderrChannel.pipe[1]);
803 stderrChannel.pipe[1] = -1;
805 if (stderrChannel.pipe[0] != -1)
806 ::fcntl(stderrChannel.pipe[0], F_SETFL, ::fcntl(stderrChannel.pipe[0], F_GETFL) | O_NONBLOCK);
810failChildProcess(
const QProcessPrivate *d,
const char *description,
int code)
noexcept
812 ChildError error = {};
814 qstrncpy(error.function, description,
sizeof(error.function));
815 qt_safe_write(d->childStartedPipe[1], &error,
sizeof(error));
819void QProcess::failChildProcessModifier(
const char *description,
int error)
noexcept
822 failChildProcess(d_func(), description, -error);
826static const char *applyProcessParameters(
const QProcess::UnixProcessParameters ¶ms)
830 bool ignore_sigpipe = params.flags.testFlag(QProcess::UnixProcessFlag::IgnoreSigPipe);
832 QtVforkSafe::change_sigpipe(SIG_IGN);
833 if (params.flags.testFlag(QProcess::UnixProcessFlag::ResetSignalHandlers)) {
834 struct sigaction sa = {};
835 sa.sa_handler = SIG_DFL;
836 for (
int sig = 1; sig < NSIG; ++sig) {
837 if (!ignore_sigpipe || sig != SIGPIPE)
838 QtVforkSafe::sigaction(sig, &sa,
nullptr);
844 sigprocmask(SIG_SETMASK, &set,
nullptr);
849 if (params.flags.testFlag(QProcess::UnixProcessFlag::CloseFileDescriptors)) {
851 int fd = qMax(STDERR_FILENO + 1, params.lowestFileDescriptorToClose);
852#ifdef CLOSE_RANGE_CLOEXEC
858 r = close_range(fd, INT_MAX, CLOSE_RANGE_CLOEXEC);
865 int max_fd = INT_MAX;
866 if (
struct rlimit limit; getrlimit(RLIMIT_NOFILE, &limit) == 0)
867 max_fd = limit.rlim_cur;
868 for ( ; fd < max_fd; ++fd)
869 fcntl(fd, F_SETFD, FD_CLOEXEC);
874 if (params.flags.testFlag(QProcess::UnixProcessFlag::CreateNewSession)) {
881 if (params.flags.testFlag(QProcess::UnixProcessFlag::DisconnectControllingTerminal)) {
883 if (
int fd = open(_PATH_TTY, O_RDONLY | O_NOCTTY); fd >= 0) {
885 int r = ioctl(fd, TIOCNOTTY);
886 int savedErrno = errno;
897 if (params.flags.testFlag(QProcess::UnixProcessFlag::DisableCoreDumps)) {
898 if (
struct rlimit lim; getrlimit(RLIMIT_CORE, &lim) == 0 && lim.rlim_cur) {
903 (
void) setrlimit(RLIMIT_CORE, &lim);
910 if (params.flags.testFlag(QProcess::UnixProcessFlag::ResetIds)) {
911 int r = setgid(getgid());
912 r = setuid(getuid());
920static void callChildProcessModifier(
const QProcessPrivate *d)
noexcept
923 if (d->unixExtras->childProcessModifier)
924 d->unixExtras->childProcessModifier();
925 } QT_CATCH (std::exception &e) {
926 failChildProcess(d, e.what(), FakeErrnoForThrow);
928 failChildProcess(d,
"throw", FakeErrnoForThrow);
937void QChildProcess::startProcess()
const noexcept
943 qt_safe_close(d->childStartedPipe[0]);
946 if (workingDirectory >= 0 && fchdir(workingDirectory) == -1)
947 failChildProcess(d,
"fchdir", errno);
949 bool sigpipeHandled =
false;
950 bool sigmaskHandled =
false;
954 callChildProcessModifier(d);
957 if (
const char *what = applyProcessParameters(d->unixExtras->processParameters))
958 failChildProcess(d, what, errno);
960 auto flags = d->unixExtras->processParameters.flags;
961 using P = QProcess::UnixProcessFlag;
962 sigpipeHandled = flags.testAnyFlags(P::ResetSignalHandlers | P::IgnoreSigPipe);
963 sigmaskHandled = flags.testFlag(P::ResetSignalHandlers);
965 if (!sigpipeHandled) {
967 QtVforkSafe::change_sigpipe(SIG_DFL);
969 if (!sigmaskHandled) {
977 qt_safe_execv(argv[0], argv);
979 qt_safe_execve(argv[0], argv, envp);
980 failChildProcess(d,
"execve", errno);
983bool QProcessPrivate::processStarted(QString *errorMessage)
988 ssize_t ret = qt_safe_read(childStartedPipe[0], &buf,
sizeof(buf));
991 stateNotifier->setEnabled(
false);
992 stateNotifier->disconnect(q);
994 qt_safe_close(childStartedPipe[0]);
995 childStartedPipe[0] = -1;
997#if defined (QPROCESS_DEBUG)
998 qDebug(
"QProcessPrivate::processStarted() == %s", ret <= 0 ?
"true" :
"false");
1002 if (stateNotifier) {
1003 QObjectPrivate::connect(stateNotifier, &QSocketNotifier::activated,
this,
1004 &QProcessPrivate::_q_processDied);
1005 stateNotifier->setSocket(forkfd);
1006 stateNotifier->setEnabled(
true);
1008 if (stdoutChannel.notifier)
1009 stdoutChannel.notifier->setEnabled(
true);
1010 if (stderrChannel.notifier)
1011 stderrChannel.notifier->setEnabled(
true);
1018 *errorMessage = startFailureErrorMessage(buf, ret);
1023qint64 QProcessPrivate::bytesAvailableInChannel(
const Channel *channel)
const
1025 Q_ASSERT(channel->pipe[0] != INVALID_Q_PIPE);
1027 qint64 available = 0;
1028 if (::ioctl(channel->pipe[0], FIONREAD, (
char *) &nbytes) >= 0)
1029 available = (qint64) nbytes;
1030#if defined (QPROCESS_DEBUG)
1031 qDebug(
"QProcessPrivate::bytesAvailableInChannel(%d) == %lld",
int(channel - &stdinChannel), available);
1036qint64 QProcessPrivate::readFromChannel(
const Channel *channel,
char *data, qint64 maxlen)
1038 Q_ASSERT(channel->pipe[0] != INVALID_Q_PIPE);
1039 qint64 bytesRead = qt_safe_read(channel->pipe[0], data, maxlen);
1040#if defined QPROCESS_DEBUG
1041 int save_errno = errno;
1042 qDebug(
"QProcessPrivate::readFromChannel(%d, %p \"%s\", %lld) == %lld",
1043 int(channel - &stdinChannel),
1044 data, QtDebugUtils::toPrintable(data, bytesRead, 16).constData(), maxlen, bytesRead);
1047 if (bytesRead == -1 && errno == EWOULDBLOCK)
1053
1054qint64 QProcess::writeData(
const char *data, qint64 len)
1058 if (d->stdinChannel.closed) {
1059#if defined QPROCESS_DEBUG
1060 qDebug(
"QProcess::writeData(%p \"%s\", %lld) == 0 (write channel closing)",
1061 data, QtDebugUtils::toPrintable(data, len, 16).constData(), len);
1066 d->write(data, len);
1067 if (d->stdinChannel.notifier)
1068 d->stdinChannel.notifier->setEnabled(
true);
1070#if defined QPROCESS_DEBUG
1071 qDebug(
"QProcess::writeData(%p \"%s\", %lld) == %lld (written to buffer)",
1072 data, QtDebugUtils::toPrintable(data, len, 16).constData(), len, len);
1077bool QProcessPrivate::_q_canWrite()
1079 if (writeBuffer.isEmpty()) {
1080 if (stdinChannel.notifier)
1081 stdinChannel.notifier->setEnabled(
false);
1082#if defined QPROCESS_DEBUG
1083 qDebug(
"QProcessPrivate::canWrite(), not writing anything (empty write buffer).");
1088 const bool writeSucceeded = writeToStdin();
1090 if (writeBuffer.isEmpty() && stdinChannel.closed)
1091 closeWriteChannel();
1092 else if (stdinChannel.notifier)
1093 stdinChannel.notifier->setEnabled(!writeBuffer.isEmpty());
1095 return writeSucceeded;
1098bool QProcessPrivate::writeToStdin()
1100 const char *data = writeBuffer.readPointer();
1101 const qint64 bytesToWrite = writeBuffer.nextDataBlockSize();
1103 qint64 written = qt_safe_write_nosignal(stdinChannel.pipe[1], data, bytesToWrite);
1104#if defined QPROCESS_DEBUG
1105 qDebug(
"QProcessPrivate::writeToStdin(), write(%p \"%s\", %lld) == %lld", data,
1106 QtDebugUtils::toPrintable(data, bytesToWrite, 16).constData(), bytesToWrite, written);
1108 qDebug(
"QProcessPrivate::writeToStdin(), failed to write (%ls)", qUtf16Printable(qt_error_string(errno)));
1110 if (written == -1) {
1114 if (errno == EAGAIN)
1117 closeChannel(&stdinChannel);
1118 setErrorAndEmit(QProcess::WriteError);
1121 writeBuffer.free(written);
1122 if (!emittedBytesWritten && written != 0) {
1123 emittedBytesWritten =
true;
1124 emit q_func()->bytesWritten(written);
1125 emittedBytesWritten =
false;
1130void QProcessPrivate::terminateProcess()
1132#if defined (QPROCESS_DEBUG)
1133 qDebug(
"QProcessPrivate::terminateProcess() pid=%jd", intmax_t(pid));
1136 ::kill(pid, SIGTERM);
1139void QProcessPrivate::killProcess()
1141#if defined (QPROCESS_DEBUG)
1142 qDebug(
"QProcessPrivate::killProcess() pid=%jd", intmax_t(pid));
1145 ::kill(pid, SIGKILL);
1148bool QProcessPrivate::waitForStarted(
const QDeadlineTimer &deadline)
1150#if defined (QPROCESS_DEBUG)
1151 const qint64 msecs = deadline.remainingTime();
1152 qDebug(
"QProcessPrivate::waitForStarted(%lld) waiting for child to start (fd = %d)",
1153 msecs, childStartedPipe[0]);
1156 pollfd pfd = qt_make_pollfd(childStartedPipe[0], POLLIN);
1158 if (qt_safe_poll(&pfd, 1, deadline) == 0) {
1159 setError(QProcess::Timedout);
1160#if defined (QPROCESS_DEBUG)
1161 qDebug(
"QProcessPrivate::waitForStarted(%lld) == false (timed out)", msecs);
1166 bool startedEmitted = _q_startupNotification();
1167#if defined (QPROCESS_DEBUG)
1168 qDebug(
"QProcessPrivate::waitForStarted() == %s", startedEmitted ?
"true" :
"false");
1170 return startedEmitted;
1173bool QProcessPrivate::waitForReadyRead(
const QDeadlineTimer &deadline)
1175#if defined (QPROCESS_DEBUG)
1176 qDebug(
"QProcessPrivate::waitForReadyRead(%lld)", deadline.remainingTime());
1180 QProcessPoller poller(*
this);
1182 int ret = poller.poll(deadline);
1188 setError(QProcess::Timedout);
1194 bool readyReadEmitted =
false;
1195 if (qt_pollfd_check(poller.stdoutPipe(), POLLIN) && _q_canReadStandardOutput())
1196 readyReadEmitted =
true;
1197 if (qt_pollfd_check(poller.stderrPipe(), POLLIN) && _q_canReadStandardError())
1198 readyReadEmitted =
true;
1200 if (readyReadEmitted)
1203 if (qt_pollfd_check(poller.stdinPipe(), POLLOUT))
1207 if (processState == QProcess::NotRunning)
1212 if (qt_pollfd_check(poller.forkfd(), POLLIN)) {
1220bool QProcessPrivate::waitForBytesWritten(
const QDeadlineTimer &deadline)
1222#if defined (QPROCESS_DEBUG)
1223 qDebug(
"QProcessPrivate::waitForBytesWritten(%lld)", deadline.remainingTime());
1226 while (!writeBuffer.isEmpty()) {
1227 QProcessPoller poller(*
this);
1229 int ret = poller.poll(deadline);
1236 setError(QProcess::Timedout);
1240 if (qt_pollfd_check(poller.stdinPipe(), POLLOUT))
1241 return _q_canWrite();
1243 if (qt_pollfd_check(poller.stdoutPipe(), POLLIN))
1244 _q_canReadStandardOutput();
1246 if (qt_pollfd_check(poller.stderrPipe(), POLLIN))
1247 _q_canReadStandardError();
1250 if (processState == QProcess::NotRunning)
1253 if (qt_pollfd_check(poller.forkfd(), POLLIN)) {
1262bool QProcessPrivate::waitForFinished(
const QDeadlineTimer &deadline)
1264#if defined (QPROCESS_DEBUG)
1265 qDebug(
"QProcessPrivate::waitForFinished(%lld)", deadline.remainingTime());
1269 QProcessPoller poller(*
this);
1271 int ret = poller.poll(deadline);
1277 setError(QProcess::Timedout);
1281 if (qt_pollfd_check(poller.stdinPipe(), POLLOUT))
1284 if (qt_pollfd_check(poller.stdoutPipe(), POLLIN))
1285 _q_canReadStandardOutput();
1287 if (qt_pollfd_check(poller.stderrPipe(), POLLIN))
1288 _q_canReadStandardError();
1291 if (processState == QProcess::NotRunning)
1294 if (qt_pollfd_check(poller.forkfd(), POLLIN)) {
1302void QProcessPrivate::waitForDeadChild()
1304 Q_ASSERT(forkfd != -1);
1307 forkfd_info info = {};
1310 QT_EINTR_LOOP(ret, forkfd_wait(forkfd, &info,
nullptr));
1312 exitCode = info.status;
1313 exitStatus = info.code == CLD_EXITED ? QProcess::NormalExit : QProcess::CrashExit;
1315 delete stateNotifier;
1316 stateNotifier =
nullptr;
1318 QT_EINTR_LOOP(ret, forkfd_close(forkfd));
1321#if defined QPROCESS_DEBUG
1322 qDebug() <<
"QProcessPrivate::waitForDeadChild() dead with exitCode"
1323 << exitCode <<
", crashed?" << (info.code != CLD_EXITED);
1327bool QProcessPrivate::startDetached(qint64 *pid)
1329 AutoPipe startedPipe, pidPipe;
1330 if (!startedPipe || !pidPipe) {
1331 setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall(
"pipe"));
1335 if (!openChannelsForDetached()) {
1342 QChildProcess childProcess(
this);
1343 if (!childProcess.ok()) {
1344 Q_ASSERT(processError != QProcess::UnknownError);
1348 childStartedPipe[1] = startedPipe[1];
1349 pid_t childPid = childProcess.doFork([&] {
1352 qt_safe_close(startedPipe[0]);
1353 qt_safe_close(pidPipe[0]);
1355 pid_t doubleForkPid;
1356 if (childProcess.startChild(&doubleForkPid) == -1)
1357 failChildProcess(
this,
"fork", errno);
1360 qt_safe_write(pidPipe[1], &doubleForkPid,
sizeof(pid_t));
1363 childStartedPipe[1] = -1;
1365 int savedErrno = errno;
1368 if (childPid == -1) {
1369 childProcess.cleanup();
1370 setErrorAndEmit(QProcess::FailedToStart, errorMessageForSyscall(
"fork", savedErrno));
1375 qt_safe_close(pidPipe[1]);
1376 qt_safe_close(startedPipe[1]);
1377 pidPipe[1] = startedPipe[1] = -1;
1384 ChildError childStatus;
1385 ssize_t startResult = qt_safe_read(startedPipe[0], &childStatus,
sizeof(childStatus));
1389 qt_safe_waitpid(childPid, &result, 0);
1391 bool success = (startResult == 0);
1392 if (success && pid) {
1394 if (qt_safe_read(pidPipe[0], &actualPid,
sizeof(pid_t)) !=
sizeof(pid_t))
1397 }
else if (!success) {
1400 childProcess.cleanup();
1401 setErrorAndEmit(QProcess::FailedToStart,
1402 startFailureErrorMessage(childStatus, startResult));