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 <kshell.h>
13 #include <qplatformdefs.h>
14 #ifdef Q_OS_WIN
15 #include <kshell_p.h>
16 #include <qt_windows.h>
17 #endif
18 
19 #include <QFile>
20 
21 /////////////////////////////
22 // public member functions //
23 /////////////////////////////
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 
40 KProcess::~KProcess() = default;
41 
43 {
44  QProcess::setProcessChannelMode(static_cast<ProcessChannelMode>(mode));
45 }
46 
48 {
49  return static_cast<OutputChannelMode>(QProcess::processChannelMode());
50 }
51 
53 {
54  Q_D(KProcess);
55 
56  d->openMode = mode;
57 }
58 
59 #define DUMMYENV "_KPROCESS_DUMMY_="
60 
62 {
63  setEnvironment(QStringList{QStringLiteral(DUMMYENV)});
64 }
65 
66 void KProcess::setEnv(const QString &name, const QString &value, bool overwrite)
67 {
68  QStringList env = environment();
69  if (env.isEmpty()) {
70  env = systemEnvironment();
71  env.removeAll(QStringLiteral(DUMMYENV));
72  }
73  QString fname(name);
74  fname.append(QLatin1Char('='));
75  for (QStringList::Iterator it = env.begin(); it != env.end(); ++it)
76  if ((*it).startsWith(fname)) {
77  if (overwrite) {
78  *it = fname.append(value);
79  setEnvironment(env);
80  }
81  return;
82  }
83  env.append(fname.append(value));
84  setEnvironment(env);
85 }
86 
87 void KProcess::unsetEnv(const QString &name)
88 {
89  QStringList env = environment();
90  if (env.isEmpty()) {
91  env = systemEnvironment();
92  env.removeAll(QStringLiteral(DUMMYENV));
93  }
94  QString fname(name);
95  fname.append(QLatin1Char('='));
96  for (QStringList::Iterator it = env.begin(); it != env.end(); ++it)
97  if ((*it).startsWith(fname)) {
98  env.erase(it);
99  if (env.isEmpty()) {
100  env.append(QStringLiteral(DUMMYENV));
101  }
102  setEnvironment(env);
103  return;
104  }
105 }
106 
107 void KProcess::setProgram(const QString &exe, const QStringList &args)
108 {
109  Q_D(KProcess);
110 
111  d->prog = exe;
112  d->args = args;
113 #ifdef Q_OS_WIN
115 #endif
116 }
117 
119 {
120  Q_D(KProcess);
121 
122  Q_ASSERT(!argv.isEmpty());
123  d->args = argv;
124  d->prog = d->args.takeFirst();
125 #ifdef Q_OS_WIN
127 #endif
128 }
129 
131 {
132  Q_D(KProcess);
133 
134  if (d->prog.isEmpty()) {
135  d->prog = arg;
136  } else {
137  d->args << arg;
138  }
139  return *this;
140 }
141 
143 {
144  Q_D(KProcess);
145 
146  if (d->prog.isEmpty()) {
147  setProgram(args);
148  } else {
149  d->args << args;
150  }
151  return *this;
152 }
153 
155 {
156  Q_D(KProcess);
157 
158  d->prog.clear();
159  d->args.clear();
160 #ifdef Q_OS_WIN
162 #endif
163 }
164 
166 {
167  Q_D(KProcess);
168 
169  KShell::Errors err;
171  if (err == KShell::NoError && !d->args.isEmpty()) {
172  d->prog = QStandardPaths::findExecutable(d->args[0]);
173  if (!d->prog.isEmpty()) {
174  d->args.removeFirst();
175 #ifdef Q_OS_WIN
177 #endif
178  return;
179  }
180  }
181 
182  d->args.clear();
183 
184 #ifdef Q_OS_UNIX
185 // #ifdef NON_FREE // ... as they ship non-POSIX /bin/sh
186 #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) && !defined(__GNU__) \
187  && !defined(__APPLE__)
188  // If /bin/sh is a symlink, we can be pretty sure that it points to a
189  // POSIX shell - the original bourne shell is about the only non-POSIX
190  // shell still in use and it is always installed natively as /bin/sh.
191  d->prog = QFile::symLinkTarget(QStringLiteral("/bin/sh"));
192  if (d->prog.isEmpty()) {
193  // Try some known POSIX shells.
194  d->prog = QStandardPaths::findExecutable(QStringLiteral("ksh"));
195  if (d->prog.isEmpty()) {
196  d->prog = QStandardPaths::findExecutable(QStringLiteral("ash"));
197  if (d->prog.isEmpty()) {
198  d->prog = QStandardPaths::findExecutable(QStringLiteral("bash"));
199  if (d->prog.isEmpty()) {
200  d->prog = QStandardPaths::findExecutable(QStringLiteral("zsh"));
201  if (d->prog.isEmpty())
202  // We're pretty much screwed, to be honest ...
203  {
204  d->prog = QStringLiteral("/bin/sh");
205  }
206  }
207  }
208  }
209  }
210 #else
211  d->prog = QStringLiteral("/bin/sh");
212 #endif
213 
214  d->args << QStringLiteral("-c") << cmd;
215 #else // Q_OS_UNIX
216  // KMacroExpander::expandMacrosShellQuote(), KShell::quoteArg() and
217  // KShell::joinArgs() may generate these for security reasons.
218  setEnv(PERCENT_VARIABLE, QStringLiteral("%"));
219 
220 #ifndef _WIN32_WCE
221  WCHAR sysdir[MAX_PATH + 1];
222  UINT size = GetSystemDirectoryW(sysdir, MAX_PATH + 1);
223  d->prog = QString::fromUtf16((const ushort *)sysdir, size);
224  d->prog += QLatin1String("\\cmd.exe");
225  setNativeArguments(QLatin1String("/V:OFF /S /C \"") + cmd + QLatin1Char('"'));
226 #else
227  d->prog = QStringLiteral("\\windows\\cmd.exe");
228  setNativeArguments(QStringLiteral("/S /C \"") + cmd + QLatin1Char('"'));
229 #endif
230 #endif
231 }
232 
234 {
235  Q_D(const KProcess);
236 
237  QStringList argv = d->args;
238  argv.prepend(d->prog);
239  return argv;
240 }
241 
243 {
244  Q_D(KProcess);
245 
246  QProcess::start(d->prog, d->args, d->openMode);
247 }
248 
249 int KProcess::execute(int msecs)
250 {
251  start();
252  if (!waitForFinished(msecs)) {
253  kill();
254  waitForFinished(-1);
255  return -2;
256  }
257  return (exitStatus() == QProcess::NormalExit) ? exitCode() : -1;
258 }
259 
260 // static
261 int KProcess::execute(const QString &exe, const QStringList &args, int msecs)
262 {
263  KProcess p;
264  p.setProgram(exe, args);
265  return p.execute(msecs);
266 }
267 
268 // static
269 int KProcess::execute(const QStringList &argv, int msecs)
270 {
271  KProcess p;
272  p.setProgram(argv);
273  return p.execute(msecs);
274 }
275 
277 {
278  Q_D(KProcess);
279 
280  qint64 pid;
281  if (!QProcess::startDetached(d->prog, d->args, workingDirectory(), &pid)) {
282  return 0;
283  }
284  return static_cast<int>(pid);
285 }
286 
287 // static
288 int KProcess::startDetached(const QString &exe, const QStringList &args)
289 {
290  qint64 pid;
291  if (!QProcess::startDetached(exe, args, QString(), &pid)) {
292  return 0;
293  }
294  return static_cast<int>(pid);
295 }
296 
297 // static
299 {
300  QStringList args = argv;
301  QString prog = args.takeFirst();
302  return startDetached(prog, args);
303 }
304 
305 #if KCOREADDONS_BUILD_DEPRECATED_SINCE(5, 78)
306 int KProcess::pid() const
307 {
308  QT_WARNING_PUSH
309  QT_WARNING_DISABLE_CLANG("-Wdeprecated-declarations")
310  QT_WARNING_DISABLE_GCC("-Wdeprecated-declarations")
311 #ifdef Q_OS_UNIX
312  return static_cast<int>(QProcess::pid());
313 #else
314  return QProcess::pid() ? QProcess::pid()->dwProcessId : 0;
315 #endif
316  QT_WARNING_POP
317 }
318 #endif
319 
320 #include "moc_kprocess.cpp"
void setNextOpenMode(QIODevice::OpenMode mode)
Set the QIODevice open mode the process will be opened in.
Definition: kprocess.cpp:52
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:165
QString & append(QChar ch)
Child process invocation, monitoring and control.
Definition: kprocess.h:33
std::unique_ptr< KProcessPrivate > const d_ptr
Definition: kprocess.h:320
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:130
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:42
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:233
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:154
void setEnv(const QString &name, const QString &value, bool overwrite=true)
Adds the variable name to the process&#39; environment.
Definition: kprocess.cpp:66
QString symLinkTarget() const const
bool isEmpty() const const
int removeAll(const T &value)
void clearEnvironment()
Empties the process&#39; environment.
Definition: kprocess.cpp:61
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:46
void unsetEnv(const QString &name)
Removes the variable name from the process&#39; environment.
Definition: kprocess.cpp:87
void start()
Start the process.
Definition: kprocess.cpp:242
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:49
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:249
void prepend(const T &value)
int pid() const
Obtain the process&#39; ID as known to the system.
Definition: kprocess.cpp:306
QStringList environment() const const
~KProcess() override
Destructor.
QObject * parent() const const
void setNativeArguments(const QString &arguments)
int startDetached()
Start the process and detach from it.
Definition: kprocess.cpp:276
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:67
Perform tilde expansion.
Definition: kshell.h:36
OutputChannelMode
Modes in which the output channels can be opened.
Definition: kprocess.h:42
OutputChannelMode outputChannelMode() const
Query how the output channels of the child process are handled.
Definition: kprocess.cpp:47
void setProgram(const QString &exe, const QStringList &args=QStringList())
Set the program and the command line arguments.
Definition: kprocess.cpp:107
bool waitForFinished(int msecs)
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sun Apr 11 2021 23:01:47 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.