Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qprocess_p.h
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 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// Qt-Security score:critical reason:execute-external-code
5
6#ifndef QPROCESS_P_H
7#define QPROCESS_P_H
8
9//
10// W A R N I N G
11// -------------
12//
13// This file is not part of the Qt API. It exists purely as an
14// implementation detail. This header file may change from version to
15// version without notice, or even be removed.
16//
17// We mean it.
18//
19
20#include "QtCore/qprocess.h"
21#include "QtCore/qstringlist.h"
22#include "QtCore/qhash.h"
23#include "QtCore/qmap.h"
24#include "QtCore/qshareddata.h"
25#include "QtCore/qdeadlinetimer.h"
26#include "private/qiodevice_p.h"
27
29
30#ifdef Q_OS_UNIX
31#include <QtCore/private/qorderedmutexlocker_p.h>
32#endif
33
34#ifdef Q_OS_WIN
35#include "QtCore/qt_windows.h"
36typedef HANDLE Q_PIPE;
37#define INVALID_Q_PIPE INVALID_HANDLE_VALUE
38#else
39typedef int Q_PIPE;
40#define INVALID_Q_PIPE -1
41#endif
42
43QT_BEGIN_NAMESPACE
44
45class QSocketNotifier;
46class QWindowsPipeReader;
47class QWindowsPipeWriter;
48class QWinEventNotifier;
49
50#ifdef Q_OS_WIN
51class QProcEnvKey : public QString
52{
53public:
54 QProcEnvKey() {}
55 explicit QProcEnvKey(const QString &other) : QString(other) {}
56 QProcEnvKey(const QProcEnvKey &other) : QString(other) {}
57 bool operator==(const QProcEnvKey &other) const { return !compare(other, Qt::CaseInsensitive); }
58};
59
60inline bool operator<(const QProcEnvKey &a, const QProcEnvKey &b)
61{
62 // On windows use case-insensitive ordering because that is how Windows needs the environment
63 // block sorted (https://msdn.microsoft.com/en-us/library/windows/desktop/ms682009(v=vs.85).aspx)
64 return a.compare(b, Qt::CaseInsensitive) < 0;
65}
66
67Q_DECLARE_TYPEINFO(QProcEnvKey, Q_RELOCATABLE_TYPE);
68
69typedef QString QProcEnvValue;
70#else
71using QProcEnvKey = QByteArray;
72
74{
75public:
76 QProcEnvValue() = default;
77 explicit QProcEnvValue(const QString &value) : stringValue(value) {}
78 explicit QProcEnvValue(const QByteArray &value) : byteValue(value) {}
79 bool operator==(const QProcEnvValue &other) const
80 {
81 return byteValue.isEmpty() && other.byteValue.isEmpty()
82 ? stringValue == other.stringValue
83 : bytes() == other.bytes();
84 }
86 {
87 if (byteValue.isEmpty() && !stringValue.isEmpty())
88 byteValue = stringValue.toLocal8Bit();
89 return byteValue;
90 }
92 {
93 if (stringValue.isEmpty() && !byteValue.isEmpty())
94 stringValue = QString::fromLocal8Bit(byteValue);
95 return stringValue;
96 }
97
100};
102#endif
103
105{
106public:
109#ifdef Q_OS_WIN
110 inline Key prepareName(const QString &name) const { return Key(name); }
111 inline QString nameToString(const Key &name) const { return name; }
112 inline Value prepareValue(const QString &value) const { return value; }
113 inline QString valueToString(const Value &value) const { return value; }
114#else
126
127 inline Key prepareName(const QString &name) const
128 {
129 const NameMapMutexLocker locker(this);
130 Key &ent = nameMap[name];
131 if (ent.isEmpty())
132 ent = name.toLocal8Bit();
133 return ent;
134 }
135 inline QString nameToString(const Key &name) const
136 {
137 const QString sname = QString::fromLocal8Bit(name);
138 {
139 const NameMapMutexLocker locker(this);
140 nameMap[sname] = name;
141 }
142 return sname;
143 }
144 inline Value prepareValue(const QString &value) const { return Value(value); }
145 inline QString valueToString(const Value &value) const { return value.string(); }
146
150 {
151 // We don't need to lock our own mutex, as this object is new and
152 // consequently not shared. For the same reason, non-const methods
153 // do not need a lock, as they detach objects (however, we need to
154 // ensure that they really detach before using prepareName()).
155 NameMapMutexLocker locker(&other);
156 nameMap = other.nameMap;
157 // We need to detach our nameMap, so that our mutex can protect it.
158 // As we are being detached, it likely would be detached a moment later anyway.
159 nameMap.detach();
160 }
161#endif
162
163 using Map = QMap<Key, Value>;
165
166#ifdef Q_OS_UNIX
167 typedef QHash<QString, Key> NameHash;
168 mutable NameHash nameMap;
169 mutable QMutex nameMapMutex;
170#endif
171
172 static QProcessEnvironment fromList(const QStringList &list);
173 QStringList toList() const;
174 QStringList keys() const;
175 void insert(const QProcessEnvironmentPrivate &other);
176};
177
178template<> Q_INLINE_TEMPLATE void QSharedDataPointer<QProcessEnvironmentPrivate>::detach()
179{
180 if (d && d->ref.loadRelaxed() == 1)
181 return;
182 QProcessEnvironmentPrivate *x = (d ? new QProcessEnvironmentPrivate(*d)
183 : new QProcessEnvironmentPrivate);
184 x->ref.ref();
185 if (d && !d->ref.deref())
186 delete d.get();
187 d.reset(x);
188}
189
190#if QT_CONFIG(process)
191
192class QProcessPrivate : public QIODevicePrivate
193{
194public:
195 Q_DECLARE_PUBLIC(QProcess)
196
197 struct Channel {
198 enum ProcessChannelType : char {
199 Normal = 0,
200 PipeSource = 1,
201 PipeSink = 2,
202 Redirect = 3
203 };
204
205 void clear();
206
207 Channel &operator=(const QString &fileName)
208 {
209 clear();
210 file = fileName;
211 type = fileName.isEmpty() ? Normal : Redirect;
212 return *this;
213 }
214
215 void pipeTo(QProcessPrivate *other)
216 {
217 clear();
218 process = other;
219 type = PipeSource;
220 }
221
222 void pipeFrom(QProcessPrivate *other)
223 {
224 clear();
225 process = other;
226 type = PipeSink;
227 }
228
229 QString file;
230 QProcessPrivate *process = nullptr;
231#ifdef Q_OS_UNIX
232 QSocketNotifier *notifier = nullptr;
233#else
234 union {
235 QWindowsPipeReader *reader = nullptr;
236 QWindowsPipeWriter *writer;
237 };
238#endif
239 Q_PIPE pipe[2] = {INVALID_Q_PIPE, INVALID_Q_PIPE};
240
241 ProcessChannelType type = Normal;
242 bool closed = false;
243 bool append = false;
244 };
245
246 QProcessPrivate();
247 virtual ~QProcessPrivate();
248
249 // private slots
250 bool _q_canReadStandardOutput();
251 bool _q_canReadStandardError();
252#ifdef Q_OS_WIN
253 qint64 pipeWriterBytesToWrite() const;
254 void _q_bytesWritten(qint64 bytes);
255 void _q_writeFailed();
256#else
257 bool _q_canWrite();
258 bool writeToStdin();
259#endif
260 bool _q_startupNotification();
261 void _q_processDied();
262
263 Channel stdinChannel;
264 Channel stdoutChannel;
265 Channel stderrChannel;
266 bool openChannels();
267 bool openChannelsForDetached();
268 bool openChannel(Channel &channel);
269 void closeChannel(Channel *channel);
270 void closeWriteChannel();
271 void closeChannels();
272 bool tryReadFromChannel(Channel *channel); // obviously, only stdout and stderr
273
274 QString program;
275 QStringList arguments;
276 QString workingDirectory;
277 QProcessEnvironment environment = QProcessEnvironment::InheritFromParent;
278#if defined(Q_OS_WIN)
279 QString nativeArguments;
280 QProcess::CreateProcessArgumentModifier modifyCreateProcessArgs;
281 QWinEventNotifier *processFinishedNotifier = nullptr;
282 Q_PROCESS_INFORMATION *pid = nullptr;
283#else
284 struct UnixExtras {
285 std::function<void(void)> childProcessModifier;
286 QProcess::UnixProcessParameters processParameters;
287 };
288 std::unique_ptr<UnixExtras> unixExtras;
289 QSocketNotifier *stateNotifier = nullptr;
290 Q_PIPE childStartedPipe[2] = {INVALID_Q_PIPE, INVALID_Q_PIPE};
291 pid_t pid = 0;
292 int forkfd = -1;
293#endif
294
295 int exitCode = 0;
296 quint8 processState = QProcess::NotRunning;
297 quint8 exitStatus = QProcess::NormalExit;
298 quint8 processError = QProcess::UnknownError;
299 quint8 processChannelMode = QProcess::SeparateChannels;
300 quint8 inputChannelMode = QProcess::ManagedInputChannel;
301 bool emittedReadyRead = false;
302 bool emittedBytesWritten = false;
303
304 void start(QIODevice::OpenMode mode);
305 void startProcess();
306#if defined(Q_OS_UNIX)
307 void commitChannels() const;
308#endif
309 bool processStarted(QString *errorMessage = nullptr);
310 void processFinished();
311 void terminateProcess();
312 void killProcess();
313#ifdef Q_OS_UNIX
314 void waitForDeadChild();
315#else
316 void findExitCode();
317#endif
318#ifdef Q_OS_WIN
319 STARTUPINFOW createStartupInfo();
320 bool callCreateProcess(QProcess::CreateProcessArguments *cpargs);
321 bool drainOutputPipes();
322#endif
323
324 bool startDetached(qint64 *pPid);
325
326 bool waitForStarted(const QDeadlineTimer &deadline);
327 bool waitForReadyRead(const QDeadlineTimer &deadline);
328 bool waitForBytesWritten(const QDeadlineTimer &deadline);
329 bool waitForFinished(const QDeadlineTimer &deadline);
330
331 qint64 bytesAvailableInChannel(const Channel *channel) const;
332 qint64 readFromChannel(const Channel *channel, char *data, qint64 maxlen);
333
334 void destroyPipe(Q_PIPE pipe[2]);
335 void cleanup();
336 void setError(QProcess::ProcessError error, const QString &description = QString());
337 void setErrorAndEmit(QProcess::ProcessError error, const QString &description = QString());
338
339 const QProcessEnvironmentPrivate *environmentPrivate() const
340 { return environment.d.constData(); }
341};
342
343#endif // QT_CONFIG(process)
344
345QT_END_NAMESPACE
346
347#endif // QPROCESS_P_H
QByteArray byteValue
Definition qprocess_p.h:98
QProcEnvValue(const QString &value)
Definition qprocess_p.h:77
bool operator==(const QProcEnvValue &other) const
Definition qprocess_p.h:79
QByteArray bytes() const
Definition qprocess_p.h:85
QProcEnvValue()=default
QString stringValue
Definition qprocess_p.h:99
QString string() const
Definition qprocess_p.h:91
QProcessEnvironmentPrivate(const QProcessEnvironmentPrivate &other)
Definition qprocess_p.h:148
Value prepareValue(const QString &value) const
Definition qprocess_p.h:144
static QProcessEnvironment fromList(const QStringList &list)
Definition qprocess.cpp:71
Key prepareName(const QString &name) const
Definition qprocess_p.h:127
QString valueToString(const Value &value) const
Definition qprocess_p.h:145
void insert(const QProcessEnvironmentPrivate &other)
Definition qprocess.cpp:100
QString nameToString(const Key &name) const
Definition qprocess_p.h:135
QStringList keys() const
Definition qprocess.cpp:89
QStringList toList() const
Definition qprocess.cpp:62
\inmodule QtCore
Definition qprocess.h:33
QT_REQUIRE_CONFIG(animation)
#define __has_include(x)
bool comparesEqual(const QFileInfo &lhs, const QFileInfo &rhs)
QT_REQUIRE_CONFIG(processenvironment)
Q_DECLARE_TYPEINFO(QProcEnvValue, Q_RELOCATABLE_TYPE)
int Q_PIPE
Definition qprocess_p.h:39
NameMapMutexLocker(const QProcessEnvironmentPrivate *d)
Definition qprocess_p.h:117
OrderedNameMapMutexLocker(const QProcessEnvironmentPrivate *d1, const QProcessEnvironmentPrivate *d2)
Definition qprocess_p.h:121