1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // Copyright (C) 2023 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 | #ifndef QPROCESS_H |
6 | #define QPROCESS_H |
7 | |
8 | #include <QtCore/qiodevice.h> |
9 | #include <QtCore/qstringlist.h> |
10 | #include <QtCore/qshareddata.h> |
11 | |
12 | #include <functional> |
13 | |
14 | QT_REQUIRE_CONFIG(processenvironment); |
15 | |
16 | #if defined(Q_OS_WIN) || defined(Q_QDOC) |
17 | struct _PROCESS_INFORMATION; |
18 | struct _SECURITY_ATTRIBUTES; |
19 | struct _STARTUPINFOW; |
20 | using Q_PROCESS_INFORMATION = _PROCESS_INFORMATION; |
21 | using Q_SECURITY_ATTRIBUTES = _SECURITY_ATTRIBUTES; |
22 | using Q_STARTUPINFO = _STARTUPINFOW; |
23 | #endif |
24 | |
25 | QT_BEGIN_NAMESPACE |
26 | |
27 | class QProcessPrivate; |
28 | class QProcessEnvironmentPrivate; |
29 | |
30 | class Q_CORE_EXPORT QProcessEnvironment |
31 | { |
32 | public: |
33 | enum Initialization { InheritFromParent }; |
34 | |
35 | QProcessEnvironment(); |
36 | QProcessEnvironment(Initialization) noexcept; |
37 | QProcessEnvironment(const QProcessEnvironment &other); |
38 | ~QProcessEnvironment(); |
39 | QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QProcessEnvironment) |
40 | QProcessEnvironment &operator=(const QProcessEnvironment &other); |
41 | |
42 | void swap(QProcessEnvironment &other) noexcept { d.swap(other&: other.d); } |
43 | |
44 | bool operator==(const QProcessEnvironment &other) const; |
45 | inline bool operator!=(const QProcessEnvironment &other) const |
46 | { return !(*this == other); } |
47 | |
48 | bool isEmpty() const; |
49 | [[nodiscard]] bool inheritsFromParent() const; |
50 | void clear(); |
51 | |
52 | bool contains(const QString &name) const; |
53 | void insert(const QString &name, const QString &value); |
54 | void remove(const QString &name); |
55 | QString value(const QString &name, const QString &defaultValue = QString()) const; |
56 | |
57 | QStringList toStringList() const; |
58 | |
59 | QStringList keys() const; |
60 | |
61 | void insert(const QProcessEnvironment &e); |
62 | |
63 | static QProcessEnvironment systemEnvironment(); |
64 | |
65 | private: |
66 | friend class QProcessPrivate; |
67 | friend class QProcessEnvironmentPrivate; |
68 | QSharedDataPointer<QProcessEnvironmentPrivate> d; |
69 | }; |
70 | |
71 | Q_DECLARE_SHARED(QProcessEnvironment) |
72 | |
73 | #if QT_CONFIG(process) |
74 | |
75 | class Q_CORE_EXPORT QProcess : public QIODevice |
76 | { |
77 | Q_OBJECT |
78 | public: |
79 | enum ProcessError { |
80 | FailedToStart, |
81 | Crashed, |
82 | Timedout, |
83 | ReadError, |
84 | WriteError, |
85 | UnknownError |
86 | }; |
87 | Q_ENUM(ProcessError) |
88 | |
89 | enum ProcessState { |
90 | NotRunning, |
91 | Starting, |
92 | Running |
93 | }; |
94 | Q_ENUM(ProcessState) |
95 | |
96 | enum ProcessChannel { |
97 | StandardOutput, |
98 | StandardError |
99 | }; |
100 | Q_ENUM(ProcessChannel) |
101 | |
102 | enum ProcessChannelMode { |
103 | SeparateChannels, |
104 | MergedChannels, |
105 | ForwardedChannels, |
106 | ForwardedOutputChannel, |
107 | ForwardedErrorChannel |
108 | }; |
109 | Q_ENUM(ProcessChannelMode) |
110 | |
111 | enum InputChannelMode { |
112 | ManagedInputChannel, |
113 | ForwardedInputChannel |
114 | }; |
115 | Q_ENUM(InputChannelMode) |
116 | |
117 | enum ExitStatus { |
118 | NormalExit, |
119 | CrashExit |
120 | }; |
121 | Q_ENUM(ExitStatus) |
122 | |
123 | explicit QProcess(QObject *parent = nullptr); |
124 | virtual ~QProcess(); |
125 | |
126 | void start(const QString &program, const QStringList &arguments = {}, OpenMode mode = ReadWrite); |
127 | void start(OpenMode mode = ReadWrite); |
128 | void startCommand(const QString &command, OpenMode mode = ReadWrite); |
129 | bool startDetached(qint64 *pid = nullptr); |
130 | bool open(OpenMode mode = ReadWrite) override; |
131 | |
132 | QString program() const; |
133 | void setProgram(const QString &program); |
134 | |
135 | QStringList arguments() const; |
136 | void setArguments(const QStringList & arguments); |
137 | |
138 | ProcessChannelMode processChannelMode() const; |
139 | void setProcessChannelMode(ProcessChannelMode mode); |
140 | InputChannelMode inputChannelMode() const; |
141 | void setInputChannelMode(InputChannelMode mode); |
142 | |
143 | ProcessChannel readChannel() const; |
144 | void setReadChannel(ProcessChannel channel); |
145 | |
146 | void closeReadChannel(ProcessChannel channel); |
147 | void closeWriteChannel(); |
148 | |
149 | void setStandardInputFile(const QString &fileName); |
150 | void setStandardOutputFile(const QString &fileName, OpenMode mode = Truncate); |
151 | void setStandardErrorFile(const QString &fileName, OpenMode mode = Truncate); |
152 | void setStandardOutputProcess(QProcess *destination); |
153 | |
154 | #if defined(Q_OS_WIN) || defined(Q_QDOC) |
155 | QString nativeArguments() const; |
156 | void setNativeArguments(const QString &arguments); |
157 | struct CreateProcessArguments |
158 | { |
159 | const wchar_t *applicationName; |
160 | wchar_t *arguments; |
161 | Q_SECURITY_ATTRIBUTES *processAttributes; |
162 | Q_SECURITY_ATTRIBUTES *threadAttributes; |
163 | bool inheritHandles; |
164 | unsigned long flags; |
165 | void *environment; |
166 | const wchar_t *currentDirectory; |
167 | Q_STARTUPINFO *startupInfo; |
168 | Q_PROCESS_INFORMATION *processInformation; |
169 | }; |
170 | typedef std::function<void(CreateProcessArguments *)> CreateProcessArgumentModifier; |
171 | CreateProcessArgumentModifier createProcessArgumentsModifier() const; |
172 | void setCreateProcessArgumentsModifier(CreateProcessArgumentModifier modifier); |
173 | #endif // Q_OS_WIN || Q_QDOC |
174 | #if defined(Q_OS_UNIX) || defined(Q_QDOC) |
175 | std::function<void(void)> childProcessModifier() const; |
176 | void setChildProcessModifier(const std::function<void(void)> &modifier); |
177 | |
178 | enum class UnixProcessFlag : quint32 { |
179 | ResetSignalHandlers = 0x0001, // like POSIX_SPAWN_SETSIGDEF |
180 | IgnoreSigPipe = 0x0002, |
181 | // some room if we want to add IgnoreSigHup or so |
182 | CloseFileDescriptors = 0x0010, |
183 | UseVFork = 0x0020, // like POSIX_SPAWN_USEVFORK |
184 | }; |
185 | Q_DECLARE_FLAGS(UnixProcessFlags, UnixProcessFlag) |
186 | struct UnixProcessParameters |
187 | { |
188 | UnixProcessFlags flags = {}; |
189 | int lowestFileDescriptorToClose = 0; |
190 | |
191 | quint32 _reserved[6] {}; |
192 | }; |
193 | UnixProcessParameters unixProcessParameters() const noexcept; |
194 | void setUnixProcessParameters(const UnixProcessParameters ¶ms); |
195 | void setUnixProcessParameters(UnixProcessFlags flagsOnly); |
196 | #endif |
197 | |
198 | QString workingDirectory() const; |
199 | void setWorkingDirectory(const QString &dir); |
200 | |
201 | void setEnvironment(const QStringList &environment); |
202 | QStringList environment() const; |
203 | void setProcessEnvironment(const QProcessEnvironment &environment); |
204 | QProcessEnvironment processEnvironment() const; |
205 | |
206 | QProcess::ProcessError error() const; |
207 | QProcess::ProcessState state() const; |
208 | |
209 | qint64 processId() const; |
210 | |
211 | bool waitForStarted(int msecs = 30000); |
212 | bool waitForReadyRead(int msecs = 30000) override; |
213 | bool waitForBytesWritten(int msecs = 30000) override; |
214 | bool waitForFinished(int msecs = 30000); |
215 | |
216 | QByteArray readAllStandardOutput(); |
217 | QByteArray readAllStandardError(); |
218 | |
219 | int exitCode() const; |
220 | QProcess::ExitStatus exitStatus() const; |
221 | |
222 | // QIODevice |
223 | qint64 bytesToWrite() const override; |
224 | bool isSequential() const override; |
225 | void close() override; |
226 | |
227 | static int execute(const QString &program, const QStringList &arguments = {}); |
228 | static bool startDetached(const QString &program, const QStringList &arguments = {}, |
229 | const QString &workingDirectory = QString(), qint64 *pid = nullptr); |
230 | |
231 | static QStringList systemEnvironment(); |
232 | |
233 | static QString nullDevice(); |
234 | |
235 | static QStringList splitCommand(QStringView command); |
236 | |
237 | public Q_SLOTS: |
238 | void terminate(); |
239 | void kill(); |
240 | |
241 | Q_SIGNALS: |
242 | void started(QPrivateSignal); |
243 | void finished(int exitCode, QProcess::ExitStatus exitStatus = NormalExit); |
244 | void errorOccurred(QProcess::ProcessError error); |
245 | void stateChanged(QProcess::ProcessState state, QPrivateSignal); |
246 | |
247 | void readyReadStandardOutput(QPrivateSignal); |
248 | void readyReadStandardError(QPrivateSignal); |
249 | |
250 | protected: |
251 | void setProcessState(ProcessState state); |
252 | |
253 | // QIODevice |
254 | qint64 readData(char *data, qint64 maxlen) override; |
255 | qint64 writeData(const char *data, qint64 len) override; |
256 | |
257 | private: |
258 | Q_DECLARE_PRIVATE(QProcess) |
259 | Q_DISABLE_COPY(QProcess) |
260 | |
261 | #if QT_VERSION < QT_VERSION_CHECK(7,0,0) |
262 | // ### Qt7: Remove this struct and the virtual function; they're here only |
263 | // to cause build errors in Qt 5 code that wasn't updated to Qt 6's |
264 | // setChildProcessModifier() |
265 | struct Use_setChildProcessModifier_Instead {}; |
266 | QT_DEPRECATED_X("Use setChildProcessModifier() instead" ) |
267 | virtual Use_setChildProcessModifier_Instead setupChildProcess(); |
268 | #endif |
269 | |
270 | Q_PRIVATE_SLOT(d_func(), bool _q_canReadStandardOutput()) |
271 | Q_PRIVATE_SLOT(d_func(), bool _q_canReadStandardError()) |
272 | #ifdef Q_OS_UNIX |
273 | Q_PRIVATE_SLOT(d_func(), bool _q_canWrite()) |
274 | #endif |
275 | Q_PRIVATE_SLOT(d_func(), bool _q_startupNotification()) |
276 | Q_PRIVATE_SLOT(d_func(), void _q_processDied()) |
277 | }; |
278 | |
279 | #ifdef Q_OS_UNIX |
280 | Q_DECLARE_OPERATORS_FOR_FLAGS(QProcess::UnixProcessFlags) |
281 | #endif |
282 | |
283 | #endif // QT_CONFIG(process) |
284 | |
285 | QT_END_NAMESPACE |
286 | |
287 | #endif // QPROCESS_H |
288 | |