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 struct MutexLocker {
116 };
117 struct OrderedMutexLocker {
120 };
121#else
122 inline Key prepareName(const QString &name) const
123 {
124 Key &ent = nameMap[name];
125 if (ent.isEmpty())
126 ent = name.toLocal8Bit();
127 return ent;
128 }
129 inline QString nameToString(const Key &name) const
130 {
131 const QString sname = QString::fromLocal8Bit(name);
132 nameMap[sname] = name;
133 return sname;
134 }
135 inline Value prepareValue(const QString &value) const { return Value(value); }
136 inline QString valueToString(const Value &value) const { return value.string(); }
137
149
153 {
154 // This being locked ensures that the functions that only assign
155 // d pointers don't need explicit locking.
156 // We don't need to lock our own mutex, as this object is new and
157 // consequently not shared. For the same reason, non-const methods
158 // do not need a lock, as they detach objects (however, we need to
159 // ensure that they really detach before using prepareName()).
160 MutexLocker locker(&other);
161 vars = other.vars;
162 nameMap = other.nameMap;
163 // We need to detach our members, so that our mutex can protect them.
164 // As we are being detached, they likely would be detached a moment later anyway.
165 vars.detach();
166 nameMap.detach();
167 }
168#endif
169
170 using Map = QMap<Key, Value>;
172
173#ifdef Q_OS_UNIX
174 typedef QHash<QString, Key> NameHash;
175 mutable NameHash nameMap;
176
177 mutable QMutex mutex;
178#endif
179
180 static QProcessEnvironment fromList(const QStringList &list);
181 QStringList toList() const;
182 QStringList keys() const;
183 void insert(const QProcessEnvironmentPrivate &other);
184};
185
186template<> Q_INLINE_TEMPLATE void QSharedDataPointer<QProcessEnvironmentPrivate>::detach()
187{
188 if (d && d->ref.loadRelaxed() == 1)
189 return;
190 QProcessEnvironmentPrivate *x = (d ? new QProcessEnvironmentPrivate(*d)
191 : new QProcessEnvironmentPrivate);
192 x->ref.ref();
193 if (d && !d->ref.deref())
194 delete d.get();
195 d.reset(x);
196}
197
198#if QT_CONFIG(process)
199
200class QProcessPrivate : public QIODevicePrivate
201{
202public:
203 Q_DECLARE_PUBLIC(QProcess)
204
205 struct Channel {
206 enum ProcessChannelType : char {
207 Normal = 0,
208 PipeSource = 1,
209 PipeSink = 2,
210 Redirect = 3
211 };
212
213 void clear();
214
215 Channel &operator=(const QString &fileName)
216 {
217 clear();
218 file = fileName;
219 type = fileName.isEmpty() ? Normal : Redirect;
220 return *this;
221 }
222
223 void pipeTo(QProcessPrivate *other)
224 {
225 clear();
226 process = other;
227 type = PipeSource;
228 }
229
230 void pipeFrom(QProcessPrivate *other)
231 {
232 clear();
233 process = other;
234 type = PipeSink;
235 }
236
237 QString file;
238 QProcessPrivate *process = nullptr;
239#ifdef Q_OS_UNIX
240 QSocketNotifier *notifier = nullptr;
241#else
242 union {
243 QWindowsPipeReader *reader = nullptr;
244 QWindowsPipeWriter *writer;
245 };
246#endif
247 Q_PIPE pipe[2] = {INVALID_Q_PIPE, INVALID_Q_PIPE};
248
249 ProcessChannelType type = Normal;
250 bool closed = false;
251 bool append = false;
252 };
253
254 QProcessPrivate();
255 virtual ~QProcessPrivate();
256
257 // private slots
258 bool _q_canReadStandardOutput();
259 bool _q_canReadStandardError();
260#ifdef Q_OS_WIN
261 qint64 pipeWriterBytesToWrite() const;
262 void _q_bytesWritten(qint64 bytes);
263 void _q_writeFailed();
264#else
265 bool _q_canWrite();
266 bool writeToStdin();
267#endif
268 bool _q_startupNotification();
269 void _q_processDied();
270
271 Channel stdinChannel;
272 Channel stdoutChannel;
273 Channel stderrChannel;
274 bool openChannels();
275 bool openChannelsForDetached();
276 bool openChannel(Channel &channel);
277 void closeChannel(Channel *channel);
278 void closeWriteChannel();
279 void closeChannels();
280 bool tryReadFromChannel(Channel *channel); // obviously, only stdout and stderr
281
282 QString program;
283 QStringList arguments;
284 QString workingDirectory;
285 QProcessEnvironment environment = QProcessEnvironment::InheritFromParent;
286#if defined(Q_OS_WIN)
287 QString nativeArguments;
288 QProcess::CreateProcessArgumentModifier modifyCreateProcessArgs;
289 QWinEventNotifier *processFinishedNotifier = nullptr;
290 Q_PROCESS_INFORMATION *pid = nullptr;
291#else
292 struct UnixExtras {
293 std::function<void(void)> childProcessModifier;
294 QProcess::UnixProcessParameters processParameters;
295 };
296 std::unique_ptr<UnixExtras> unixExtras;
297 QSocketNotifier *stateNotifier = nullptr;
298 Q_PIPE childStartedPipe[2] = {INVALID_Q_PIPE, INVALID_Q_PIPE};
299 pid_t pid = 0;
300 int forkfd = -1;
301#endif
302
303 int exitCode = 0;
304 quint8 processState = QProcess::NotRunning;
305 quint8 exitStatus = QProcess::NormalExit;
306 quint8 processError = QProcess::UnknownError;
307 quint8 processChannelMode = QProcess::SeparateChannels;
308 quint8 inputChannelMode = QProcess::ManagedInputChannel;
309 bool emittedReadyRead = false;
310 bool emittedBytesWritten = false;
311
312 void start(QIODevice::OpenMode mode);
313 void startProcess();
314#if defined(Q_OS_UNIX)
315 void commitChannels() const;
316#endif
317 bool processStarted(QString *errorMessage = nullptr);
318 void processFinished();
319 void terminateProcess();
320 void killProcess();
321#ifdef Q_OS_UNIX
322 void waitForDeadChild();
323#else
324 void findExitCode();
325#endif
326#ifdef Q_OS_WIN
327 STARTUPINFOW createStartupInfo();
328 bool callCreateProcess(QProcess::CreateProcessArguments *cpargs);
329 bool drainOutputPipes();
330#endif
331
332 bool startDetached(qint64 *pPid);
333
334 bool waitForStarted(const QDeadlineTimer &deadline);
335 bool waitForReadyRead(const QDeadlineTimer &deadline);
336 bool waitForBytesWritten(const QDeadlineTimer &deadline);
337 bool waitForFinished(const QDeadlineTimer &deadline);
338
339 qint64 bytesAvailableInChannel(const Channel *channel) const;
340 qint64 readFromChannel(const Channel *channel, char *data, qint64 maxlen);
341
342 void destroyPipe(Q_PIPE pipe[2]);
343 void cleanup();
344 void setError(QProcess::ProcessError error, const QString &description = QString());
345 void setErrorAndEmit(QProcess::ProcessError error, const QString &description = QString());
346
347 const QProcessEnvironmentPrivate *environmentPrivate() const
348 { return environment.d.constData(); }
349};
350
351#endif // QT_CONFIG(process)
352
353QT_END_NAMESPACE
354
355#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:151
Value prepareValue(const QString &value) const
Definition qprocess_p.h:135
static QProcessEnvironment fromList(const QStringList &list)
Definition qprocess.cpp:71
Key prepareName(const QString &name) const
Definition qprocess_p.h:122
QString valueToString(const Value &value) const
Definition qprocess_p.h:136
void insert(const QProcessEnvironmentPrivate &other)
Definition qprocess.cpp:100
QString nameToString(const Key &name) const
Definition qprocess_p.h:129
QStringList keys() const
Definition qprocess.cpp:89
QStringList toList() const
Definition qprocess.cpp:62
\inmodule QtCore
Definition qprocess.h:33
Combined button and popup list for selecting options.
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
MutexLocker(const QProcessEnvironmentPrivate *d)
Definition qprocess_p.h:140
OrderedMutexLocker(const QProcessEnvironmentPrivate *d1, const QProcessEnvironmentPrivate *d2)
Definition qprocess_p.h:144