KCoreAddons

kprocess.cpp
1 /*
2  This file is part of the KDE libraries
3 
4  SPDX-FileCopyrightText: 2007 Oswald Buddenhagen <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 #include "kprocess_p.h"
10 
11 #include <QStandardPaths>
12 #include <qplatformdefs.h>
13 #include <kshell.h>
14 #ifdef Q_OS_WIN
15 # include <qt_windows.h>
16 # include <kshell_p.h>
17 #endif
18 
19 #include <QFile>
20 
22 // public member functions //
24 
26  QProcess(parent),
27  d_ptr(new KProcessPrivate(this))
28 {
30 }
31 
32 KProcess::KProcess(KProcessPrivate *d, QObject *parent) :
33  QProcess(parent),
34  d_ptr(d)
35 {
36  d_ptr->q_ptr = this;
38 }
39 
41 {
42  delete d_ptr;
43 }
44 
46 {
47  QProcess::setProcessChannelMode(static_cast<ProcessChannelMode>(mode));
48 }
49 
51 {
52  return static_cast<OutputChannelMode>(QProcess::processChannelMode());
53 }
54 
56 {
57  Q_D(KProcess);
58 
59  d->openMode = mode;
60 }
61 
62 #define DUMMYENV "_KPROCESS_DUMMY_="
63 
65 {
66  setEnvironment(QStringList { QStringLiteral(DUMMYENV) });
67 }
68 
69 void KProcess::setEnv(const QString &name, const QString &value, bool overwrite)
70 {
71  QStringList env = environment();
72  if (env.isEmpty()) {
73  env = systemEnvironment();
74  env.removeAll(QStringLiteral(DUMMYENV));
75  }
76  QString fname(name);
77  fname.append(QLatin1Char('='));
78  for (QStringList::Iterator it = env.begin(); it != env.end(); ++it)
79  if ((*it).startsWith(fname)) {
80  if (overwrite) {
81  *it = fname.append(value);
82  setEnvironment(env);
83  }
84  return;
85  }
86  env.append(fname.append(value));
87  setEnvironment(env);
88 }
89 
90 void KProcess::unsetEnv(const QString &name)
91 {
92  QStringList env = environment();
93  if (env.isEmpty()) {
94  env = systemEnvironment();
95  env.removeAll(QStringLiteral(DUMMYENV));
96  }
97  QString fname(name);
98  fname.append(QLatin1Char('='));
99  for (QStringList::Iterator it = env.begin(); it != env.end(); ++it)
100  if ((*it).startsWith(fname)) {
101  env.erase(it);
102  if (env.isEmpty()) {
103  env.append(QStringLiteral(DUMMYENV));
104  }
105  setEnvironment(env);
106  return;
107  }
108 }
109 
110 void KProcess::setProgram(const QString &exe, const QStringList &args)
111 {
112  Q_D(KProcess);
113 
114  d->prog = exe;
115  d->args = args;
116 #ifdef Q_OS_WIN
118 #endif
119 }
120 
122 {
123  Q_D(KProcess);
124 
125  Q_ASSERT(!argv.isEmpty());
126  d->args = argv;
127  d->prog = d->args.takeFirst();
128 #ifdef Q_OS_WIN
130 #endif
131 }
132 
134 {
135  Q_D(KProcess);
136 
137  if (d->prog.isEmpty()) {
138  d->prog = arg;
139  } else {
140  d->args << arg;
141  }
142  return *this;
143 }
144 
146 {
147  Q_D(KProcess);
148 
149  if (d->prog.isEmpty()) {
150  setProgram(args);
151  } else {
152  d->args << args;
153  }
154  return *this;
155 }
156 
158 {
159  Q_D(KProcess);
160 
161  d->prog.clear();
162  d->args.clear();
163 #ifdef Q_OS_WIN
165 #endif
166 }
167 
169 {
170  Q_D(KProcess);
171 
172  KShell::Errors err;
173  d->args = KShell::splitArgs(
175  if (err == KShell::NoError && !d->args.isEmpty()) {
176  d->prog = QStandardPaths::findExecutable(d->args[0]);
177  if (!d->prog.isEmpty()) {
178  d->args.removeFirst();
179 #ifdef Q_OS_WIN
181 #endif
182  return;
183  }
184  }
185 
186  d->args.clear();
187 
188 #ifdef Q_OS_UNIX
189 // #ifdef NON_FREE // ... as they ship non-POSIX /bin/sh
190 # if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) && !defined(__GNU__) && !defined(__APPLE__)
191  // If /bin/sh is a symlink, we can be pretty sure that it points to a
192  // POSIX shell - the original bourne shell is about the only non-POSIX
193  // shell still in use and it is always installed natively as /bin/sh.
194  d->prog = QFile::symLinkTarget(QStringLiteral("/bin/sh"));
195  if (d->prog.isEmpty()) {
196  // Try some known POSIX shells.
197  d->prog = QStandardPaths::findExecutable(QStringLiteral("ksh"));
198  if (d->prog.isEmpty()) {
199  d->prog = QStandardPaths::findExecutable(QStringLiteral("ash"));
200  if (d->prog.isEmpty()) {
201  d->prog = QStandardPaths::findExecutable(QStringLiteral("bash"));
202  if (d->prog.isEmpty()) {
203  d->prog = QStandardPaths::findExecutable(QStringLiteral("zsh"));
204  if (d->prog.isEmpty())
205  // We're pretty much screwed, to be honest ...
206  {
207  d->prog = QStringLiteral("/bin/sh");
208  }
209  }
210  }
211  }
212  }
213 # else
214  d->prog = QStringLiteral("/bin/sh");
215 # endif
216 
217  d->args << QStringLiteral("-c") << cmd;
218 #else // Q_OS_UNIX
219  // KMacroExpander::expandMacrosShellQuote(), KShell::quoteArg() and
220  // KShell::joinArgs() may generate these for security reasons.
221  setEnv(PERCENT_VARIABLE, QStringLiteral("%"));
222 
223 #ifndef _WIN32_WCE
224  WCHAR sysdir[MAX_PATH + 1];
225  UINT size = GetSystemDirectoryW(sysdir, MAX_PATH + 1);
226  d->prog = QString::fromUtf16((const ushort *) sysdir, size);
227  d->prog += QLatin1String("\\cmd.exe");
228  setNativeArguments(QLatin1String("/V:OFF /S /C \"") + cmd + QLatin1Char('"'));
229 #else
230  d->prog = QStringLiteral("\\windows\\cmd.exe");
231  setNativeArguments(QStringLiteral("/S /C \"") + cmd + QLatin1Char('"'));
232 #endif
233 #endif
234 }
235 
237 {
238  Q_D(const KProcess);
239 
240  QStringList argv = d->args;
241  argv.prepend(d->prog);
242  return argv;
243 }
244 
246 {
247  Q_D(KProcess);
248 
249  QProcess::start(d->prog, d->args, d->openMode);
250 }
251 
252 int KProcess::execute(int msecs)
253 {
254  start();
255  if (!waitForFinished(msecs)) {
256  kill();
257  waitForFinished(-1);
258  return -2;
259  }
260  return (exitStatus() == QProcess::NormalExit) ? exitCode() : -1;
261 }
262 
263 // static
264 int KProcess::execute(const QString &exe, const QStringList &args, int msecs)
265 {
266  KProcess p;
267  p.setProgram(exe, args);
268  return p.execute(msecs);
269 }
270 
271 // static
272 int KProcess::execute(const QStringList &argv, int msecs)
273 {
274  KProcess p;
275  p.setProgram(argv);
276  return p.execute(msecs);
277 }
278 
280 {
281  Q_D(KProcess);
282 
283  qint64 pid;
284  if (!QProcess::startDetached(d->prog, d->args, workingDirectory(), &pid)) {
285  return 0;
286  }
287  return static_cast<int>(pid);
288 }
289 
290 // static
291 int KProcess::startDetached(const QString &exe, const QStringList &args)
292 {
293  qint64 pid;
294  if (!QProcess::startDetached(exe, args, QString(), &pid)) {
295  return 0;
296  }
297  return static_cast<int>(pid);
298 }
299 
300 // static
302 {
303  QStringList args = argv;
304  QString prog = args.takeFirst();
305  return startDetached(prog, args);
306 }
307 
308 int KProcess::pid() const
309 {
310 #ifdef Q_OS_UNIX
311  return static_cast<int>(QProcess::pid());
312 #else
313  return QProcess::pid() ? QProcess::pid()->dwProcessId : 0;
314 #endif
315 }
316 
317 #include "moc_kprocess.cpp"
void setNextOpenMode(QIODevice::OpenMode mode)
Set the QIODevice open mode the process will be opened in.
Definition: kprocess.cpp:55
void setShellCommand(const QString &cmd)
Set a command to execute through a shell (a POSIX sh on *NIX and cmd.exe on Windows).
Definition: kprocess.cpp:168
QString & append(QChar ch)
Child process invocation, monitoring and control.
Definition: kprocess.h:31
void kill()
QStringList systemEnvironment()
bool startDetached(qint64 *pid)
QString findExecutable(const QString &executableName, const QStringList &paths)
KProcess & operator<<(const QString &arg)
Append an element to the command line argument list for this process.
Definition: kprocess.cpp:133
typedef OpenMode
QList::iterator erase(QList::iterator pos)
void setOutputChannelMode(OutputChannelMode mode)
Set how to handle the output channels of the child process.
Definition: kprocess.cpp:45
KProcess(QObject *parent=nullptr)
Constructor.
Definition: kprocess.cpp:25
QProcess::ProcessChannelMode processChannelMode() const const
void append(const T &value)
virtual qint64 size() const const
QStringList program() const
Obtain the currently set program and arguments.
Definition: kprocess.cpp:236
Q_PID pid() const const
QString fromUtf16(const ushort *unicode, int size)
void clearProgram()
Clear the program and command line argument list.
Definition: kprocess.cpp:157
void setEnv(const QString &name, const QString &value, bool overwrite=true)
Adds the variable name to the process&#39; environment.
Definition: kprocess.cpp:69
QString symLinkTarget() const const
bool isEmpty() const const
int removeAll(const T &value)
void clearEnvironment()
Empties the process&#39; environment.
Definition: kprocess.cpp:64
Errors
Status codes from splitArgs()
Definition: kshell.h:78
typedef Iterator
KCOREADDONS_EXPORT QStringList splitArgs(const QString &cmd, Options flags=NoOptions, Errors *err=nullptr)
Splits cmd according to system shell word splitting and quoting rules.
Definition: kshell_unix.cpp:58
void unsetEnv(const QString &name)
Removes the variable name from the process&#39; environment.
Definition: kprocess.cpp:90
KProcessPrivate *const d_ptr
Definition: kprocess.h:315
void start()
Start the process.
Definition: kprocess.cpp:245
QList::iterator end()
void setProcessChannelMode(QProcess::ProcessChannelMode mode)
void setEnvironment(const QStringList &environment)
Both standard output and standard error are forwarded to the parent process&#39; respective channel...
Definition: kprocess.h:48
T takeFirst()
QString workingDirectory() const const
Success.
Definition: kshell.h:82
int execute(int msecs=-1)
Start the process, wait for it to finish, and return the exit code.
Definition: kprocess.cpp:252
void prepend(const T &value)
int pid() const
Obtain the process&#39; ID as known to the system.
Definition: kprocess.cpp:308
QStringList environment() const const
~KProcess() override
Destructor.
Definition: kprocess.cpp:40
QObject * parent() const const
void setNativeArguments(const QString &arguments)
int startDetached()
Start the process and detach from it.
Definition: kprocess.cpp:279
QProcess::ExitStatus exitStatus() const const
QList::iterator begin()
int exitCode() const const
void start(const QString &program, const QStringList &arguments, QIODevice::OpenMode mode)
Put the parser into full shell mode and bail out if a too complex construct is encountered.
Definition: kshell.h:68
Perform tilde expansion.
Definition: kshell.h:37
OutputChannelMode
Modes in which the output channels can be opened.
Definition: kprocess.h:41
OutputChannelMode outputChannelMode() const
Query how the output channels of the child process are handled.
Definition: kprocess.cpp:50
void setProgram(const QString &exe, const QStringList &args=QStringList())
Set the program and the command line arguments.
Definition: kprocess.cpp:110
bool waitForFinished(int msecs)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Tue Jul 14 2020 23:02:10 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.