1 /*
2     This file is part of the KDE libraries
3 
4     SPDX-FileCopyrightText: 2007 Oswald Buddenhagen <ossi@kde.org>
5 
6     SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 #ifndef KPROCESS_H
10 #define KPROCESS_H
11 
12 #include <kcoreaddons_export.h>
13 
14 #include <QProcess>
15 
16 #include <memory>
17 
18 class KProcessPrivate;
19 
20 /**
21  * \class KProcess kprocess.h <KProcess>
22  *
23  * Child process invocation, monitoring and control.
24  *
25  * This class extends QProcess by some useful functionality, overrides
26  * some defaults with saner values and wraps parts of the API into a more
27  * accessible one.
28  * Only use KProcess if you need the extra features, otherwise QProcess
29  * is the preferred way of spawning child processes.
30  *
31  * @author Oswald Buddenhagen <ossi@kde.org>
32  **/
33 class KCOREADDONS_EXPORT KProcess : public QProcess
34 {
35     Q_OBJECT
36     Q_DECLARE_PRIVATE(KProcess)
37 
38 public:
39     /**
40      * Modes in which the output channels can be opened.
41      */
42     enum OutputChannelMode {
43         SeparateChannels = QProcess::SeparateChannels,
44         /**< Standard output and standard error are handled by KProcess
45              as separate channels */
46         MergedChannels = QProcess::MergedChannels,
47         /**< Standard output and standard error are handled by KProcess
48              as one channel */
49         ForwardedChannels = QProcess::ForwardedChannels,
50         /**< Both standard output and standard error are forwarded
51              to the parent process' respective channel */
52         OnlyStdoutChannel = QProcess::ForwardedErrorChannel,
53         /**< Only standard output is handled; standard error is forwarded */
54         OnlyStderrChannel = QProcess::ForwardedOutputChannel,
55         /**< Only standard error is handled; standard output is forwarded */
56     };
57 
58     /**
59      * Constructor
60      */
61     explicit KProcess(QObject *parent = nullptr);
62 
63     /**
64      * Destructor
65      */
66     ~KProcess() override;
67 
68     /**
69      * Set how to handle the output channels of the child process.
70      *
71      * The default is ForwardedChannels, which is unlike in QProcess.
72      * Do not request more than you actually handle, as this output is
73      * simply lost otherwise.
74      *
75      * This function must be called before starting the process.
76      *
77      * @param mode the output channel handling mode
78      */
79     void setOutputChannelMode(OutputChannelMode mode);
80 
81     /**
82      * Query how the output channels of the child process are handled.
83      *
84      * @return the output channel handling mode
85      */
86     OutputChannelMode outputChannelMode() const;
87 
88     /**
89      * Set the QIODevice open mode the process will be opened in.
90      *
91      * This function must be called before starting the process, obviously.
92      *
93      * @param mode the open mode. Note that this mode is automatically
94      *   "reduced" according to the channel modes and redirections.
95      *   The default is QIODevice::ReadWrite.
96      */
97     void setNextOpenMode(QIODevice::OpenMode mode);
98 
99     /**
100      * Adds the variable @p name to the process' environment.
101      *
102      * This function must be called before starting the process.
103      *
104      * @param name the name of the environment variable
105      * @param value the new value for the environment variable
106      * @param overwrite if @c false and the environment variable is already
107      *   set, the old value will be preserved
108      */
109     void setEnv(const QString &name, const QString &value, bool overwrite = true);
110 
111     /**
112      * Removes the variable @p name from the process' environment.
113      *
114      * This function must be called before starting the process.
115      *
116      * @param name the name of the environment variable
117      */
118     void unsetEnv(const QString &name);
119 
120     /**
121      * Empties the process' environment.
122      *
123      * Note that LD_LIBRARY_PATH/DYLD_LIBRARY_PATH is automatically added
124      * on *NIX.
125      *
126      * This function must be called before starting the process.
127      */
128     void clearEnvironment();
129 
130     /**
131      * Set the program and the command line arguments.
132      *
133      * This function must be called before starting the process, obviously.
134      *
135      * @param exe the program to execute
136      * @param args the command line arguments for the program,
137      *   one per list element
138      */
139     void setProgram(const QString &exe, const QStringList &args = QStringList());
140 
141     /**
142      * @overload
143      *
144      * @param argv the program to execute and the command line arguments
145      *   for the program, one per list element
146      */
147     void setProgram(const QStringList &argv);
148 
149     /**
150      * Append an element to the command line argument list for this process.
151      *
152      * If no executable is set yet, it will be set instead.
153      *
154      * For example, doing an "ls -l /usr/local/bin" can be achieved by:
155      *  \code
156      *  KProcess p;
157      *  p << "ls" << "-l" << "/usr/local/bin";
158      *  ...
159      *  \endcode
160      *
161      * This function must be called before starting the process, obviously.
162      *
163      * @param arg the argument to add
164      * @return a reference to this KProcess
165      */
166     KProcess &operator<<(const QString &arg);
167 
168     /**
169      * @overload
170      *
171      * @param args the arguments to add
172      * @return a reference to this KProcess
173      */
174     KProcess &operator<<(const QStringList &args);
175 
176     /**
177      * Clear the program and command line argument list.
178      */
179     void clearProgram();
180 
181     /**
182      * Set a command to execute through a shell (a POSIX sh on *NIX
183      * and cmd.exe on Windows).
184      *
185      * Using this for anything but user-supplied commands is usually a bad
186      * idea, as the command's syntax depends on the platform.
187      * Redirections including pipes, etc. are better handled by the
188      * respective functions provided by QProcess.
189      *
190      * If KProcess determines that the command does not really need a
191      * shell, it will transparently execute it without one for performance
192      * reasons.
193      *
194      * This function must be called before starting the process, obviously.
195      *
196      * @param cmd the command to execute through a shell.
197      *   The caller must make sure that all filenames etc. are properly
198      *   quoted when passed as argument. Failure to do so often results in
199      *   serious security holes. See KShell::quoteArg().
200      */
201     void setShellCommand(const QString &cmd);
202 
203     /**
204      * Obtain the currently set program and arguments.
205      *
206      * @return a list, the first element being the program, the remaining ones
207      *  being command line arguments to the program.
208      */
209     QStringList program() const;
210 
211     /**
212      * Start the process.
213      *
214      * @see QProcess::start(const QString &, const QStringList &, OpenMode)
215      */
216     void start();
217 
218     /**
219      * Start the process, wait for it to finish, and return the exit code.
220      *
221      * This method is roughly equivalent to the sequence:
222      * @code
223      *   start();
224      *   waitForFinished(msecs);
225      *   return exitCode();
226      * @endcode
227      *
228      * Unlike the other execute() variants this method is not static,
229      * so the process can be parametrized properly and talked to.
230      *
231      * @param msecs time to wait for process to exit before killing it
232      * @return -2 if the process could not be started, -1 if it crashed,
233      *  otherwise its exit code
234      */
235     int execute(int msecs = -1);
236 
237     /**
238      * @overload
239      *
240      * @param exe the program to execute
241      * @param args the command line arguments for the program,
242      *   one per list element
243      * @param msecs time to wait for process to exit before killing it
244      * @return -2 if the process could not be started, -1 if it crashed,
245      *  otherwise its exit code
246      */
247     static int execute(const QString &exe, const QStringList &args = QStringList(), int msecs = -1);
248 
249     /**
250      * @overload
251      *
252      * @param argv the program to execute and the command line arguments
253      *   for the program, one per list element
254      * @param msecs time to wait for process to exit before killing it
255      * @return -2 if the process could not be started, -1 if it crashed,
256      *  otherwise its exit code
257      */
258     static int execute(const QStringList &argv, int msecs = -1);
259 
260     /**
261      * Start the process and detach from it. See QProcess::startDetached()
262      * for details.
263      *
264      * Unlike the other startDetached() variants this method is not static,
265      * so the process can be parametrized properly.
266      * @note Currently, only the setProgram()/setShellCommand() and
267      * setWorkingDirectory() parametrizations are supported.
268      *
269      * The KProcess object may be re-used immediately after calling this
270      * function.
271      *
272      * @return the PID of the started process or 0 on error
273      */
274     int startDetached();
275 
276     /**
277      * @overload
278      *
279      * @param exe the program to start
280      * @param args the command line arguments for the program,
281      *   one per list element
282      * @return the PID of the started process or 0 on error
283      */
284     static int startDetached(const QString &exe, const QStringList &args = QStringList());
285 
286     /**
287      * @overload
288      *
289      * @param argv the program to start and the command line arguments
290      *   for the program, one per list element
291      * @return the PID of the started process or 0 on error
292      */
293     static int startDetached(const QStringList &argv);
294 
295 #if KCOREADDONS_ENABLE_DEPRECATED_SINCE(5, 78)
296     /**
297      * Obtain the process' ID as known to the system.
298      *
299      * Unlike with QProcess::pid(), this is a real PID also on Windows.
300      *
301      * This function can be called only while the process is running.
302      * It cannot be applied to detached processes.
303      *
304      * @return the process ID
305      * @deprecated since 5.78, use processId()
306      */
307     KCOREADDONS_DEPRECATED_VERSION(5, 78, "Use processId()")
308     int pid() const;
309 #endif
310 
311 protected:
312     /**
313      * @internal
314      */
315     KProcess(KProcessPrivate *d, QObject *parent);
316 
317     /**
318      * @internal
319      */
320     std::unique_ptr<KProcessPrivate> const d_ptr;
321 
322 private:
323     // hide those
324 #if QT_DEPRECATED_SINCE(5, 13)
325     using QProcess::readChannelMode;
326     using QProcess::setReadChannelMode;
327 #endif
328     using QProcess::processChannelMode;
329     using QProcess::setProcessChannelMode;
330 };
331 
332 #endif
333