Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qprocess.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// Copyright (C) 2022 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5//#define QPROCESS_DEBUG
6
7#include <qdebug.h>
8#include <qdir.h>
10
11#include "qprocess.h"
12#include "qprocess_p.h"
13
14#include <qbytearray.h>
15#include <qdeadlinetimer.h>
16#include <qcoreapplication.h>
17#include <qtimer.h>
18
19#if __has_include(<paths.h>)
20#include <paths.h>
21#endif
22
24
63{
65 result.reserve(vars.size());
66 for (auto it = vars.cbegin(), end = vars.cend(); it != end; ++it)
67 result << nameToString(it.key()) + u'=' + valueToString(it.value());
68 return result;
69}
70
72{
75 end = list.constEnd();
76 for ( ; it != end; ++it) {
77 const qsizetype pos = it->indexOf(u'=', 1);
78 if (pos < 1)
79 continue;
80
81 QString value = it->mid(pos + 1);
82 QString name = *it;
83 name.truncate(pos);
84 env.insert(name, value);
85 }
86 return env;
87}
88
90{
92 result.reserve(vars.size());
93 auto it = vars.constBegin();
94 const auto end = vars.constEnd();
95 for ( ; it != end; ++it)
96 result << nameToString(it.key());
97 return result;
98}
99
101{
102 auto it = other.vars.constBegin();
103 const auto end = other.vars.constEnd();
104 for ( ; it != end; ++it)
105 vars.insert(it.key(), it.value());
106
107#ifdef Q_OS_UNIX
108 const OrderedNameMapMutexLocker locker(this, &other);
109 auto nit = other.nameMap.constBegin();
110 const auto nend = other.nameMap.constEnd();
111 for ( ; nit != nend; ++nit)
112 nameMap.insert(nit.key(), nit.value());
113#endif
114}
115
134
154
161
169
179
208{
209 if (lhs.d == rhs.d)
210 return true;
211
212 return lhs.d && rhs.d && lhs.d->vars == rhs.d->vars;
213}
214
225{
226 // Needs no locking, as no hash nodes are accessed
227 return d ? d->vars.isEmpty() : true;
228}
229
238{
239 return !d;
240}
241
252{
253 if (d.constData())
254 d->vars.clear();
255 // Unix: Don't clear d->nameMap, as the environment is likely to be
256 // re-populated with the same keys again.
257}
258
267{
268 if (!d)
269 return false;
270 return d->vars.contains(d->prepareName(name));
271}
272
286{
287 // our re-impl of detach() detaches from null
288 d.detach(); // detach before prepareName()
290}
291
301{
302 if (d.constData()) {
304 p->vars.remove(p->prepareName(name));
305 }
306}
307
315QString QProcessEnvironment::value(const QString &name, const QString &defaultValue) const
316{
317 if (!d)
318 return defaultValue;
319
320 const auto it = d->vars.constFind(d->prepareName(name));
321 if (it == d->vars.constEnd())
322 return defaultValue;
323
324 return d->valueToString(it.value());
325}
326
341{
342 if (!d)
343 return QStringList();
344 return d->toList();
345}
346
357{
358 if (!d)
359 return QStringList();
360 return d->keys();
361}
362
371{
372 if (!e.d)
373 return;
374
375 // our re-impl of detach() detaches from null
376 d->insert(*e.d);
377}
378
379#if QT_CONFIG(process)
380
381void QProcessPrivate::Channel::clear()
382{
383 switch (type) {
384 case PipeSource:
385 Q_ASSERT(process);
386 process->stdinChannel.type = Normal;
387 process->stdinChannel.process = nullptr;
388 break;
389 case PipeSink:
390 Q_ASSERT(process);
391 process->stdoutChannel.type = Normal;
392 process->stdoutChannel.process = nullptr;
393 break;
394 default:
395 break;
396 }
397
398 type = Normal;
399 file.clear();
400 process = nullptr;
401}
402
962QProcessPrivate::QProcessPrivate()
963{
964 readBufferChunkSize = QRINGBUFFER_CHUNKSIZE;
965#ifndef Q_OS_WIN
966 writeBufferChunkSize = QRINGBUFFER_CHUNKSIZE;
967#endif
968}
969
973QProcessPrivate::~QProcessPrivate()
974{
975 if (stdinChannel.process)
976 stdinChannel.process->stdoutChannel.clear();
977 if (stdoutChannel.process)
978 stdoutChannel.process->stdinChannel.clear();
979}
980
984void QProcessPrivate::setError(QProcess::ProcessError error, const QString &description)
985{
986 processError = error;
987 if (description.isEmpty()) {
988 switch (error) {
989 case QProcess::FailedToStart:
990 errorString = QProcess::tr("Process failed to start");
991 break;
992 case QProcess::Crashed:
993 errorString = QProcess::tr("Process crashed");
994 break;
995 case QProcess::Timedout:
996 errorString = QProcess::tr("Process operation timed out");
997 break;
998 case QProcess::ReadError:
999 errorString = QProcess::tr("Error reading from process");
1000 break;
1001 case QProcess::WriteError:
1002 errorString = QProcess::tr("Error writing to process");
1003 break;
1004 case QProcess::UnknownError:
1005 errorString.clear();
1006 break;
1007 }
1008 } else {
1009 errorString = description;
1010 }
1011}
1012
1016void QProcessPrivate::setErrorAndEmit(QProcess::ProcessError error, const QString &description)
1017{
1018 Q_Q(QProcess);
1019 Q_ASSERT(error != QProcess::UnknownError);
1020 setError(error, description);
1021 emit q->errorOccurred(QProcess::ProcessError(processError));
1022}
1023
1027bool QProcessPrivate::openChannels()
1028{
1029 // stdin channel.
1030 if (inputChannelMode == QProcess::ForwardedInputChannel) {
1031 if (stdinChannel.type != Channel::Normal)
1032 qWarning("QProcess::openChannels: Inconsistent stdin channel configuration");
1033 } else if (!openChannel(stdinChannel)) {
1034 return false;
1035 }
1036
1037 // stdout channel.
1038 if (processChannelMode == QProcess::ForwardedChannels
1039 || processChannelMode == QProcess::ForwardedOutputChannel) {
1040 if (stdoutChannel.type != Channel::Normal)
1041 qWarning("QProcess::openChannels: Inconsistent stdout channel configuration");
1042 } else if (!openChannel(stdoutChannel)) {
1043 return false;
1044 }
1045
1046 // stderr channel.
1047 if (processChannelMode == QProcess::ForwardedChannels
1048 || processChannelMode == QProcess::ForwardedErrorChannel
1049 || processChannelMode == QProcess::MergedChannels) {
1050 if (stderrChannel.type != Channel::Normal)
1051 qWarning("QProcess::openChannels: Inconsistent stderr channel configuration");
1052 } else if (!openChannel(stderrChannel)) {
1053 return false;
1054 }
1055
1056 return true;
1057}
1058
1062void QProcessPrivate::closeChannels()
1063{
1064 closeChannel(&stdoutChannel);
1065 closeChannel(&stderrChannel);
1066 closeChannel(&stdinChannel);
1067}
1068
1072bool QProcessPrivate::openChannelsForDetached()
1073{
1074 // stdin channel.
1075 bool needToOpen = (stdinChannel.type == Channel::Redirect
1076 || stdinChannel.type == Channel::PipeSink);
1077 if (stdinChannel.type != Channel::Normal
1078 && (!needToOpen
1079 || inputChannelMode == QProcess::ForwardedInputChannel)) {
1080 qWarning("QProcess::openChannelsForDetached: Inconsistent stdin channel configuration");
1081 }
1082 if (needToOpen && !openChannel(stdinChannel))
1083 return false;
1084
1085 // stdout channel.
1086 needToOpen = (stdoutChannel.type == Channel::Redirect
1087 || stdoutChannel.type == Channel::PipeSource);
1088 if (stdoutChannel.type != Channel::Normal
1089 && (!needToOpen
1090 || processChannelMode == QProcess::ForwardedChannels
1091 || processChannelMode == QProcess::ForwardedOutputChannel)) {
1092 qWarning("QProcess::openChannelsForDetached: Inconsistent stdout channel configuration");
1093 }
1094 if (needToOpen && !openChannel(stdoutChannel))
1095 return false;
1096
1097 // stderr channel.
1098 needToOpen = (stderrChannel.type == Channel::Redirect);
1099 if (stderrChannel.type != Channel::Normal
1100 && (!needToOpen
1101 || processChannelMode == QProcess::ForwardedChannels
1102 || processChannelMode == QProcess::ForwardedErrorChannel
1103 || processChannelMode == QProcess::MergedChannels)) {
1104 qWarning("QProcess::openChannelsForDetached: Inconsistent stderr channel configuration");
1105 }
1106 if (needToOpen && !openChannel(stderrChannel))
1107 return false;
1108
1109 return true;
1110}
1111
1116bool QProcessPrivate::tryReadFromChannel(Channel *channel)
1117{
1118 Q_Q(QProcess);
1119 if (channel->pipe[0] == INVALID_Q_PIPE)
1120 return false;
1121
1122 qint64 available = bytesAvailableInChannel(channel);
1123 if (available == 0)
1124 available = 1; // always try to read at least one byte
1125
1126 QProcess::ProcessChannel channelIdx = (channel == &stdoutChannel
1127 ? QProcess::StandardOutput
1128 : QProcess::StandardError);
1129 Q_ASSERT(readBuffers.size() > int(channelIdx));
1130 QRingBuffer &readBuffer = readBuffers[int(channelIdx)];
1131 char *ptr = readBuffer.reserve(available);
1132 qint64 readBytes = readFromChannel(channel, ptr, available);
1133 if (readBytes <= 0)
1134 readBuffer.chop(available);
1135 if (readBytes == -2) {
1136 // EWOULDBLOCK
1137 return false;
1138 }
1139 if (readBytes == -1) {
1140 setErrorAndEmit(QProcess::ReadError);
1141#if defined QPROCESS_DEBUG
1142 qDebug("QProcessPrivate::tryReadFromChannel(%d), failed to read from the process",
1143 int(channel - &stdinChannel));
1144#endif
1145 return false;
1146 }
1147 if (readBytes == 0) {
1148 // EOF
1149 closeChannel(channel);
1150#if defined QPROCESS_DEBUG
1151 qDebug("QProcessPrivate::tryReadFromChannel(%d), 0 bytes available",
1152 int(channel - &stdinChannel));
1153#endif
1154 return false;
1155 }
1156#if defined QPROCESS_DEBUG
1157 qDebug("QProcessPrivate::tryReadFromChannel(%d), read %lld bytes from the process' output",
1158 int(channel - &stdinChannel), readBytes);
1159#endif
1160
1161 if (channel->closed) {
1162 readBuffer.chop(readBytes);
1163 return false;
1164 }
1165
1166 readBuffer.chop(available - readBytes);
1167
1168 bool didRead = false;
1169 if (currentReadChannel == channelIdx) {
1170 didRead = true;
1171 if (!emittedReadyRead) {
1172 QScopedValueRollback<bool> guard(emittedReadyRead, true);
1173 emit q->readyRead();
1174 }
1175 }
1176 emit q->channelReadyRead(int(channelIdx));
1177 if (channelIdx == QProcess::StandardOutput)
1178 emit q->readyReadStandardOutput(QProcess::QPrivateSignal());
1179 else
1180 emit q->readyReadStandardError(QProcess::QPrivateSignal());
1181 return didRead;
1182}
1183
1187bool QProcessPrivate::_q_canReadStandardOutput()
1188{
1189 return tryReadFromChannel(&stdoutChannel);
1190}
1191
1195bool QProcessPrivate::_q_canReadStandardError()
1196{
1197 return tryReadFromChannel(&stderrChannel);
1198}
1199
1203void QProcessPrivate::_q_processDied()
1204{
1205#if defined QPROCESS_DEBUG
1206 qDebug("QProcessPrivate::_q_processDied()");
1207#endif
1208
1209 // in case there is data in the pipeline and this slot by chance
1210 // got called before the read notifications, call these functions
1211 // so the data is made available before we announce death.
1212#ifdef Q_OS_WIN
1213 drainOutputPipes();
1214#else
1215 _q_canReadStandardOutput();
1216 _q_canReadStandardError();
1217#endif
1218
1219 // Slots connected to signals emitted by the functions called above
1220 // might call waitFor*(), which would synchronously reap the process.
1221 // So check the state to avoid trying to reap a second time.
1222 if (processState != QProcess::NotRunning)
1223 processFinished();
1224}
1225
1229void QProcessPrivate::processFinished()
1230{
1231 Q_Q(QProcess);
1232#if defined QPROCESS_DEBUG
1233 qDebug("QProcessPrivate::processFinished()");
1234#endif
1235
1236#ifdef Q_OS_UNIX
1237 waitForDeadChild();
1238#else
1239 findExitCode();
1240#endif
1241
1242 cleanup();
1243
1244 if (exitStatus == QProcess::CrashExit)
1245 setErrorAndEmit(QProcess::Crashed);
1246
1247 // we received EOF now:
1248 emit q->readChannelFinished();
1249 // in the future:
1250 //emit q->standardOutputClosed();
1251 //emit q->standardErrorClosed();
1252
1253 emit q->finished(exitCode, QProcess::ExitStatus(exitStatus));
1254
1255#if defined QPROCESS_DEBUG
1256 qDebug("QProcessPrivate::processFinished(): process is dead");
1257#endif
1258}
1259
1263bool QProcessPrivate::_q_startupNotification()
1264{
1265 Q_Q(QProcess);
1266#if defined QPROCESS_DEBUG
1267 qDebug("QProcessPrivate::startupNotification()");
1268#endif
1269
1271 if (processStarted(&errorMessage)) {
1272 q->setProcessState(QProcess::Running);
1273 emit q->started(QProcess::QPrivateSignal());
1274 return true;
1275 }
1276
1277 q->setProcessState(QProcess::NotRunning);
1278 setErrorAndEmit(QProcess::FailedToStart, errorMessage);
1279#ifdef Q_OS_UNIX
1280 waitForDeadChild();
1281#endif
1282 cleanup();
1283 return false;
1284}
1285
1289void QProcessPrivate::closeWriteChannel()
1290{
1291#if defined QPROCESS_DEBUG
1292 qDebug("QProcessPrivate::closeWriteChannel()");
1293#endif
1294
1295 closeChannel(&stdinChannel);
1296}
1297
1301QProcess::QProcess(QObject *parent)
1302 : QIODevice(*new QProcessPrivate, parent)
1303{
1304#if defined QPROCESS_DEBUG
1305 qDebug("QProcess::QProcess(%p)", parent);
1306#endif
1307}
1308
1315QProcess::~QProcess()
1316{
1317 Q_D(QProcess);
1318 if (d->processState != NotRunning) {
1319 qWarning().nospace()
1320 << "QProcess: Destroyed while process (" << QDir::toNativeSeparators(program()) << ") is still running.";
1321 kill();
1323 }
1324 d->cleanup();
1325}
1326
1335QProcess::ProcessChannelMode QProcess::processChannelMode() const
1336{
1337 Q_D(const QProcess);
1338 return ProcessChannelMode(d->processChannelMode);
1339}
1340
1352void QProcess::setProcessChannelMode(ProcessChannelMode mode)
1353{
1354 Q_D(QProcess);
1355 d->processChannelMode = mode;
1356}
1357
1365QProcess::InputChannelMode QProcess::inputChannelMode() const
1366{
1367 Q_D(const QProcess);
1368 return InputChannelMode(d->inputChannelMode);
1369}
1370
1380void QProcess::setInputChannelMode(InputChannelMode mode)
1381{
1382 Q_D(QProcess);
1383 d->inputChannelMode = mode;
1384}
1385
1391QProcess::ProcessChannel QProcess::readChannel() const
1392{
1393 Q_D(const QProcess);
1394 return ProcessChannel(d->currentReadChannel);
1395}
1396
1405void QProcess::setReadChannel(ProcessChannel channel)
1406{
1408}
1409
1420void QProcess::closeReadChannel(ProcessChannel channel)
1421{
1422 Q_D(QProcess);
1423
1424 if (channel == StandardOutput)
1425 d->stdoutChannel.closed = true;
1426 else
1427 d->stderrChannel.closed = true;
1428}
1429
1448void QProcess::closeWriteChannel()
1449{
1450 Q_D(QProcess);
1451 d->stdinChannel.closed = true; // closing
1452 if (bytesToWrite() == 0)
1453 d->closeWriteChannel();
1454}
1455
1477void QProcess::setStandardInputFile(const QString &fileName)
1478{
1479 Q_D(QProcess);
1480 d->stdinChannel = fileName;
1481}
1482
1512void QProcess::setStandardOutputFile(const QString &fileName, OpenMode mode)
1513{
1514 Q_ASSERT(mode == Append || mode == Truncate);
1515 Q_D(QProcess);
1516
1517 d->stdoutChannel = fileName;
1518 d->stdoutChannel.append = mode == Append;
1519}
1520
1539void QProcess::setStandardErrorFile(const QString &fileName, OpenMode mode)
1540{
1541 Q_ASSERT(mode == Append || mode == Truncate);
1542 Q_D(QProcess);
1543
1544 d->stderrChannel = fileName;
1545 d->stderrChannel.append = mode == Append;
1546}
1547
1560void QProcess::setStandardOutputProcess(QProcess *destination)
1561{
1562 QProcessPrivate *dfrom = d_func();
1563 QProcessPrivate *dto = destination->d_func();
1564 dfrom->stdoutChannel.pipeTo(dto);
1565 dto->stdinChannel.pipeFrom(dfrom);
1566}
1567
1568#if defined(Q_OS_WIN) || defined(Q_QDOC)
1569
1579QString QProcess::nativeArguments() const
1580{
1581 Q_D(const QProcess);
1582 return d->nativeArguments;
1583}
1584
1602void QProcess::setNativeArguments(const QString &arguments)
1603{
1604 Q_D(QProcess);
1605 d->nativeArguments = arguments;
1606}
1607
1618QProcess::CreateProcessArgumentModifier QProcess::createProcessArgumentsModifier() const
1619{
1620 Q_D(const QProcess);
1621 return d->modifyCreateProcessArgs;
1622}
1623
1635void QProcess::setCreateProcessArgumentsModifier(CreateProcessArgumentModifier modifier)
1636{
1637 Q_D(QProcess);
1638 d->modifyCreateProcessArgs = modifier;
1639}
1640
1641#endif
1642
1643#if defined(Q_OS_UNIX) || defined(Q_QDOC)
1654std::function<void(void)> QProcess::childProcessModifier() const
1655{
1656 Q_D(const QProcess);
1657 return d->unixExtras ? d->unixExtras->childProcessModifier : std::function<void(void)>();
1658}
1659
1707void QProcess::setChildProcessModifier(const std::function<void(void)> &modifier)
1708{
1709 Q_D(QProcess);
1710 if (!d->unixExtras)
1711 d->unixExtras.reset(new QProcessPrivate::UnixExtras);
1712 d->unixExtras->childProcessModifier = modifier;
1713}
1714
1765auto QProcess::unixProcessParameters() const noexcept -> UnixProcessParameters
1766{
1767 Q_D(const QProcess);
1768 return d->unixExtras ? d->unixExtras->processParameters : UnixProcessParameters{};
1769}
1770
1789void QProcess::setUnixProcessParameters(const UnixProcessParameters &params)
1790{
1791 Q_D(QProcess);
1792 if (!d->unixExtras)
1793 d->unixExtras.reset(new QProcessPrivate::UnixExtras);
1794 d->unixExtras->processParameters = params;
1795}
1796
1808void QProcess::setUnixProcessParameters(UnixProcessFlags flagsOnly)
1809{
1810 Q_D(QProcess);
1811 if (!d->unixExtras)
1812 d->unixExtras.reset(new QProcessPrivate::UnixExtras);
1813 d->unixExtras->processParameters = { flagsOnly };
1814}
1815#endif
1816
1826QString QProcess::workingDirectory() const
1827{
1828 Q_D(const QProcess);
1829 return d->workingDirectory;
1830}
1831
1839void QProcess::setWorkingDirectory(const QString &dir)
1840{
1841 Q_D(QProcess);
1842 d->workingDirectory = dir;
1843}
1844
1851qint64 QProcess::processId() const
1852{
1853 Q_D(const QProcess);
1854#ifdef Q_OS_WIN
1855 return d->pid ? d->pid->dwProcessId : 0;
1856#else
1857 return d->pid;
1858#endif
1859}
1860
1866void QProcess::close()
1867{
1868 Q_D(QProcess);
1869 emit aboutToClose();
1870 while (waitForBytesWritten(-1))
1871 ;
1872 kill();
1873 waitForFinished(-1);
1874 d->setWriteChannelCount(0);
1876}
1877
1880bool QProcess::isSequential() const
1881{
1882 return true;
1883}
1884
1887qint64 QProcess::bytesToWrite() const
1888{
1889#ifdef Q_OS_WIN
1890 return d_func()->pipeWriterBytesToWrite();
1891#else
1892 return QIODevice::bytesToWrite();
1893#endif
1894}
1895
1901QProcess::ProcessError QProcess::error() const
1902{
1903 Q_D(const QProcess);
1904 return ProcessError(d->processError);
1905}
1906
1912QProcess::ProcessState QProcess::state() const
1913{
1914 Q_D(const QProcess);
1915 return ProcessState(d->processState);
1916}
1917
1932void QProcess::setEnvironment(const QStringList &environment)
1933{
1934 setProcessEnvironment(QProcessEnvironmentPrivate::fromList(environment));
1935}
1936
1946QStringList QProcess::environment() const
1947{
1948 Q_D(const QProcess);
1949 return d->environment.toStringList();
1950}
1951
1965void QProcess::setProcessEnvironment(const QProcessEnvironment &environment)
1966{
1967 Q_D(QProcess);
1968 d->environment = environment;
1969}
1970
1980QProcessEnvironment QProcess::processEnvironment() const
1981{
1982 Q_D(const QProcess);
1983 return d->environment;
1984}
1985
2006bool QProcess::waitForStarted(int msecs)
2007{
2008 Q_D(QProcess);
2009 if (d->processState == QProcess::Starting)
2010 return d->waitForStarted(QDeadlineTimer(msecs));
2011
2012 return d->processState == QProcess::Running;
2013}
2014
2017bool QProcess::waitForReadyRead(int msecs)
2018{
2019 Q_D(QProcess);
2020
2021 if (d->processState == QProcess::NotRunning)
2022 return false;
2023 if (d->currentReadChannel == QProcess::StandardOutput && d->stdoutChannel.closed)
2024 return false;
2025 if (d->currentReadChannel == QProcess::StandardError && d->stderrChannel.closed)
2026 return false;
2027
2028 QDeadlineTimer deadline(msecs);
2029 if (d->processState == QProcess::Starting) {
2030 bool started = d->waitForStarted(deadline);
2031 if (!started)
2032 return false;
2033 }
2034
2035 return d->waitForReadyRead(deadline);
2036}
2037
2040bool QProcess::waitForBytesWritten(int msecs)
2041{
2042 Q_D(QProcess);
2043 if (d->processState == QProcess::NotRunning)
2044 return false;
2045
2046 QDeadlineTimer deadline(msecs);
2047 if (d->processState == QProcess::Starting) {
2048 bool started = d->waitForStarted(deadline);
2049 if (!started)
2050 return false;
2051 }
2052
2053 return d->waitForBytesWritten(deadline);
2054}
2055
2075bool QProcess::waitForFinished(int msecs)
2076{
2077 Q_D(QProcess);
2078 if (d->processState == QProcess::NotRunning)
2079 return false;
2080
2081 QDeadlineTimer deadline(msecs);
2082 if (d->processState == QProcess::Starting) {
2083 bool started = d->waitForStarted(deadline);
2084 if (!started)
2085 return false;
2086 }
2087
2088 return d->waitForFinished(deadline);
2089}
2090
2096void QProcess::setProcessState(ProcessState state)
2097{
2098 Q_D(QProcess);
2099 if (d->processState == state)
2100 return;
2101 d->processState = state;
2102 emit stateChanged(state, QPrivateSignal());
2103}
2104
2105#if QT_VERSION < QT_VERSION_CHECK(7,0,0)
2109auto QProcess::setupChildProcess() -> Use_setChildProcessModifier_Instead
2110{
2111 Q_UNREACHABLE_RETURN({});
2112}
2113#endif
2114
2117qint64 QProcess::readData(char *data, qint64 maxlen)
2118{
2119 Q_D(QProcess);
2120 Q_UNUSED(data);
2121 if (!maxlen)
2122 return 0;
2123 if (d->processState == QProcess::NotRunning)
2124 return -1; // EOF
2125 return 0;
2126}
2127
2135QByteArray QProcess::readAllStandardOutput()
2136{
2137 ProcessChannel tmp = readChannel();
2138 setReadChannel(StandardOutput);
2139 QByteArray data = readAll();
2140 setReadChannel(tmp);
2141 return data;
2142}
2143
2151QByteArray QProcess::readAllStandardError()
2152{
2153 Q_D(QProcess);
2155 if (d->processChannelMode == MergedChannels) {
2156 qWarning("QProcess::readAllStandardError: Called with MergedChannels");
2157 } else {
2158 ProcessChannel tmp = readChannel();
2159 setReadChannel(StandardError);
2160 data = readAll();
2161 setReadChannel(tmp);
2162 }
2163 return data;
2164}
2165
2205void QProcess::start(const QString &program, const QStringList &arguments, OpenMode mode)
2206{
2207 Q_D(QProcess);
2208 if (d->processState != NotRunning) {
2209 qWarning("QProcess::start: Process is already running");
2210 return;
2211 }
2212 if (program.isEmpty()) {
2213 d->setErrorAndEmit(QProcess::FailedToStart, tr("No program defined"));
2214 return;
2215 }
2216
2217 d->program = program;
2218 d->arguments = arguments;
2219
2220 d->start(mode);
2221}
2222
2232void QProcess::start(OpenMode mode)
2233{
2234 Q_D(QProcess);
2235 if (d->processState != NotRunning) {
2236 qWarning("QProcess::start: Process is already running");
2237 return;
2238 }
2239 if (d->program.isEmpty()) {
2240 d->setErrorAndEmit(QProcess::FailedToStart, tr("No program defined"));
2241 return;
2242 }
2243
2244 d->start(mode);
2245}
2246
2281void QProcess::startCommand(const QString &command, OpenMode mode)
2282{
2283 QStringList args = splitCommand(command);
2284 if (args.isEmpty()) {
2285 qWarning("QProcess::startCommand: empty or whitespace-only command was provided");
2286 return;
2287 }
2288 const QString program = args.takeFirst();
2290}
2291
2339bool QProcess::startDetached(qint64 *pid)
2340{
2341 Q_D(QProcess);
2342 if (d->processState != NotRunning) {
2343 qWarning("QProcess::startDetached: Process is already running");
2344 return false;
2345 }
2346 if (d->program.isEmpty()) {
2347 d->setErrorAndEmit(QProcess::FailedToStart, tr("No program defined"));
2348 return false;
2349 }
2350 return d->startDetached(pid);
2351}
2352
2364bool QProcess::open(OpenMode mode)
2365{
2366 Q_D(QProcess);
2367 if (d->processState != NotRunning) {
2368 qWarning("QProcess::start: Process is already running");
2369 return false;
2370 }
2371 if (d->program.isEmpty()) {
2372 qWarning("QProcess::start: program not set");
2373 return false;
2374 }
2375
2376 d->start(mode);
2377 return true;
2378}
2379
2380void QProcessPrivate::start(QIODevice::OpenMode mode)
2381{
2382 Q_Q(QProcess);
2383#if defined QPROCESS_DEBUG
2384 qDebug() << "QProcess::start(" << program << ',' << arguments << ',' << mode << ')';
2385#endif
2386
2387 if (stdinChannel.type != QProcessPrivate::Channel::Normal)
2388 mode &= ~QIODevice::WriteOnly; // not open for writing
2389 if (stdoutChannel.type != QProcessPrivate::Channel::Normal &&
2390 (stderrChannel.type != QProcessPrivate::Channel::Normal ||
2391 processChannelMode == QProcess::MergedChannels))
2392 mode &= ~QIODevice::ReadOnly; // not open for reading
2393 if (mode == 0)
2395 if ((mode & QIODevice::ReadOnly) == 0) {
2396 if (stdoutChannel.type == QProcessPrivate::Channel::Normal)
2397 q->setStandardOutputFile(q->nullDevice());
2398 if (stderrChannel.type == QProcessPrivate::Channel::Normal
2399 && processChannelMode != QProcess::MergedChannels)
2400 q->setStandardErrorFile(q->nullDevice());
2401 }
2402
2403 q->QIODevice::open(mode);
2404
2405 if (q->isReadable() && processChannelMode != QProcess::MergedChannels)
2406 setReadChannelCount(2);
2407
2408 stdinChannel.closed = false;
2409 stdoutChannel.closed = false;
2410 stderrChannel.closed = false;
2411
2412 exitCode = 0;
2413 exitStatus = QProcess::NormalExit;
2414 processError = QProcess::UnknownError;
2415 errorString.clear();
2416 startProcess();
2417}
2418
2428QStringList QProcess::splitCommand(QStringView command)
2429{
2431 QString tmp;
2432 int quoteCount = 0;
2433 bool inQuote = false;
2434
2435 // handle quoting. tokens can be surrounded by double quotes
2436 // "hello world". three consecutive double quotes represent
2437 // the quote character itself.
2438 for (int i = 0; i < command.size(); ++i) {
2439 if (command.at(i) == u'"') {
2440 ++quoteCount;
2441 if (quoteCount == 3) {
2442 // third consecutive quote
2443 quoteCount = 0;
2444 tmp += command.at(i);
2445 }
2446 continue;
2447 }
2448 if (quoteCount) {
2449 if (quoteCount == 1)
2450 inQuote = !inQuote;
2451 quoteCount = 0;
2452 }
2453 if (!inQuote && command.at(i).isSpace()) {
2454 if (!tmp.isEmpty()) {
2455 args += tmp;
2456 tmp.clear();
2457 }
2458 } else {
2459 tmp += command.at(i);
2460 }
2461 }
2462 if (!tmp.isEmpty())
2463 args += tmp;
2464
2465 return args;
2466}
2467
2475QString QProcess::program() const
2476{
2477 Q_D(const QProcess);
2478 return d->program;
2479}
2480
2494void QProcess::setProgram(const QString &program)
2495{
2496 Q_D(QProcess);
2497 if (d->processState != NotRunning) {
2498 qWarning("QProcess::setProgram: Process is already running");
2499 return;
2500 }
2501 d->program = program;
2502}
2503
2511QStringList QProcess::arguments() const
2512{
2513 Q_D(const QProcess);
2514 return d->arguments;
2515}
2516
2525void QProcess::setArguments(const QStringList &arguments)
2526{
2527 Q_D(QProcess);
2528 if (d->processState != NotRunning) {
2529 qWarning("QProcess::setProgram: Process is already running");
2530 return;
2531 }
2532 d->arguments = arguments;
2533}
2534
2551void QProcess::terminate()
2552{
2553 Q_D(QProcess);
2554 d->terminateProcess();
2555}
2556
2565void QProcess::kill()
2566{
2567 Q_D(QProcess);
2568 d->killProcess();
2569}
2570
2576int QProcess::exitCode() const
2577{
2578 Q_D(const QProcess);
2579 return d->exitCode;
2580}
2581
2591QProcess::ExitStatus QProcess::exitStatus() const
2592{
2593 Q_D(const QProcess);
2594 return ExitStatus(d->exitStatus);
2595}
2596
2614int QProcess::execute(const QString &program, const QStringList &arguments)
2615{
2616 QProcess process;
2617 process.setProcessChannelMode(ForwardedChannels);
2618 process.start(program, arguments);
2619 if (!process.waitForFinished(-1) || process.error() == FailedToStart)
2620 return -2;
2621 return process.exitStatus() == QProcess::NormalExit ? process.exitCode() : -1;
2622}
2623
2643bool QProcess::startDetached(const QString &program,
2644 const QStringList &arguments,
2645 const QString &workingDirectory,
2646 qint64 *pid)
2647{
2648 QProcess process;
2649 process.setProgram(program);
2650 process.setArguments(arguments);
2651 process.setWorkingDirectory(workingDirectory);
2652 return process.startDetached(pid);
2653}
2654
2674QStringList QProcess::systemEnvironment()
2675{
2676 return QProcessEnvironment::systemEnvironment().toStringList();
2677}
2678
2708QString QProcess::nullDevice()
2709{
2710#ifdef Q_OS_WIN
2711 return QStringLiteral("\\\\.\\NUL");
2712#elif defined(_PATH_DEVNULL)
2713 return QStringLiteral(_PATH_DEVNULL);
2714#else
2715 return QStringLiteral("/dev/null");
2716#endif
2717}
2718
2719#endif // QT_CONFIG(process)
2720
2722
2723#include "moc_qprocess.cpp"
IOBluetoothL2CAPChannel * channel
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
static QString toNativeSeparators(const QString &pathName)
Definition qdir.cpp:929
\inmodule QtCore \reentrant
Definition qiodevice.h:34
virtual qint64 bytesToWrite() const
For buffered devices, this function returns the number of bytes waiting to be written.
virtual void close()
First emits aboutToClose(), then closes the device and sets its OpenMode to NotOpen.
void setCurrentReadChannel(int channel)
bool isEmpty() const noexcept
Definition qlist.h:401
value_type takeFirst()
Definition qlist.h:566
const_iterator constBegin() const noexcept
Definition qlist.h:632
const_iterator constEnd() const noexcept
Definition qlist.h:633
const_iterator ConstIterator
Definition qlist.h:250
iterator insert(const Key &key, const T &value)
Definition qmap.h:688
bool contains(const Key &key) const
Definition qmap.h:341
const_iterator cend() const
Definition qmap.h:605
size_type remove(const Key &key)
Definition qmap.h:300
const_iterator cbegin() const
Definition qmap.h:601
const_iterator constFind(const Key &key) const
Definition qmap.h:655
void clear()
Definition qmap.h:289
bool isEmpty() const
Definition qmap.h:269
const_iterator constBegin() const
Definition qmap.h:600
size_type size() const
Definition qmap.h:267
const_iterator constEnd() const
Definition qmap.h:604
\inmodule QtCore
Definition qobject.h:103
Value prepareValue(const QString &value) const
Definition qprocess_p.h:143
static QProcessEnvironment fromList(const QStringList &list)
Definition qprocess.cpp:71
Key prepareName(const QString &name) const
Definition qprocess_p.h:126
QString valueToString(const Value &value) const
Definition qprocess_p.h:144
void insert(const QProcessEnvironmentPrivate &other)
Definition qprocess.cpp:100
QString nameToString(const Key &name) const
Definition qprocess_p.h:134
QStringList keys() const
Definition qprocess.cpp:89
QStringList toList() const
Definition qprocess.cpp:62
\inmodule QtCore
Definition qprocess.h:32
QProcessEnvironment & operator=(const QProcessEnvironment &other)
Copies the contents of the other QProcessEnvironment object into this one.
Definition qprocess.cpp:174
QString value(const QString &name, const QString &defaultValue=QString()) const
Searches this QProcessEnvironment object for a variable identified by name and returns its value.
Definition qprocess.cpp:315
void remove(const QString &name)
Removes the environment variable identified by name from this QProcessEnvironment object.
Definition qprocess.cpp:300
QStringList toStringList() const
Converts this QProcessEnvironment object into a list of strings, one for each environment variable th...
Definition qprocess.cpp:340
void insert(const QString &name, const QString &value)
Inserts the environment variable of name name and contents value into this QProcessEnvironment object...
Definition qprocess.cpp:285
bool isEmpty() const
Returns true if this QProcessEnvironment object is empty: that is there are no key=value pairs set.
Definition qprocess.cpp:224
bool inheritsFromParent() const
Returns true if this QProcessEnvironment was constructed using {QProcessEnvironment::InheritFromParen...
Definition qprocess.cpp:237
bool contains(const QString &name) const
Returns true if the environment variable of name name is found in this QProcessEnvironment object.
Definition qprocess.cpp:266
QProcessEnvironment()
Creates a new QProcessEnvironment object.
Definition qprocess.cpp:133
QStringList keys() const
Definition qprocess.cpp:356
void clear()
Removes all key=value pairs from this QProcessEnvironment object, making it empty.
Definition qprocess.cpp:251
Initialization
This enum contains a token that is used to disambiguate constructors.
Definition qprocess.h:34
~QProcessEnvironment()
Frees the resources associated with this QProcessEnvironment object.
Definition qprocess.cpp:158
static QProcessEnvironment systemEnvironment()
void detach()
If the shared data object's reference count is greater than 1, this function creates a deep copy of t...
Definition qshareddata.h:40
const T * constData() const noexcept
Returns a const pointer to the shared data object.
Definition qshareddata.h:51
T * data()
Returns a pointer to the shared data object.
Definition qshareddata.h:47
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
constexpr qsizetype size() const noexcept
Returns the size of this string view, in UTF-16 code units (that is, surrogate pairs count as two for...
constexpr QChar at(qsizetype n) const noexcept
Returns the character at position n in this string view.
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1252
QSet< QString >::iterator it
QList< QVariant > arguments
else opt state
[0]
Combined button and popup list for selecting options.
Q_MULTIMEDIA_EXPORT QString errorString(HRESULT hr)
QList< QString > QStringList
Constructs a string list that contains the given string, str.
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char * destination
DBusConnection const char DBusError * error
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qDebug
[1]
Definition qlogging.h:164
#define qWarning
Definition qlogging.h:166
static ControlElement< T > * ptr(QWidget *widget)
GLenum mode
GLuint GLuint end
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum type
GLuint program
GLuint start
GLuint name
void ** params
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
GLbitfield GLuint readBuffer
bool comparesEqual(const QProcessEnvironment &lhs, const QProcessEnvironment &rhs)
Definition qprocess.cpp:207
#define INVALID_Q_PIPE
Definition qprocess_p.h:39
static void setError(QJsonObject *response, const QString &msg)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QRINGBUFFER_CHUNKSIZE
#define QStringLiteral(str)
void startProcess()
Definition main.cpp:6
#define tr(X)
#define emit
#define Q_UNUSED(x)
ptrdiff_t qsizetype
Definition qtypes.h:165
long long qint64
Definition qtypes.h:60
static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition)
Definition qurl.cpp:3517
QList< int > list
[14]
future waitForFinished()
QFile file
[0]
QDeadlineTimer deadline(30s)
QSharedPointer< T > other(t)
[5]
QString dir
[11]
QJSValueList args