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