KCoreAddons

kprocess.cpp
1/*
2 This file is part of the KDE libraries
3
4 SPDX-FileCopyrightText: 2007 Oswald Buddenhagen <ossi@kde.org>
5 SPDX-FileCopyrightText: 2022 Harald Sitter <sitter@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#include "kcoreaddons_debug.h"
11#include "kprocess_p.h"
12
13#include <QStandardPaths>
14#include <kshell.h>
15#include <qplatformdefs.h>
16#ifdef Q_OS_WIN
17#include <kshell_p.h>
18#include <qt_windows.h>
19#endif
20
21#include <QFile>
22
23/////////////////////////////
24// public member functions //
25/////////////////////////////
26
28 : QProcess(parent)
29 , d_ptr(new KProcessPrivate(this))
30{
32}
33
34KProcess::KProcess(KProcessPrivate *d, QObject *parent)
35 : QProcess(parent)
36 , d_ptr(d)
37{
38 d_ptr->q_ptr = this;
40}
41
42KProcess::~KProcess() = default;
43
48
53
55{
57
58 d->openMode = mode;
59}
60
61#define DUMMYENV "_KPROCESS_DUMMY_="
62
64{
65 setEnvironment(QStringList{QStringLiteral(DUMMYENV)});
66}
67
68void KProcess::setEnv(const QString &name, const QString &value, bool overwrite)
69{
71 if (env.isEmpty()) {
72 env = systemEnvironment();
73 env.removeAll(QStringLiteral(DUMMYENV));
74 }
75 QString fname(name);
76 fname.append(QLatin1Char('='));
77 auto it = std::find_if(env.begin(), env.end(), [&fname](const QString &s) {
78 return s.startsWith(fname);
79 });
80 if (it != env.end()) {
81 if (overwrite) {
82 *it = fname.append(value);
83 setEnvironment(env);
84 }
85 return;
86 }
87
88 env.append(fname.append(value));
89 setEnvironment(env);
90}
91
92void KProcess::unsetEnv(const QString &name)
93{
95 if (env.isEmpty()) {
96 env = systemEnvironment();
97 env.removeAll(QStringLiteral(DUMMYENV));
98 }
99 QString fname(name);
100 fname.append(QLatin1Char('='));
101
102 auto it = std::find_if(env.begin(), env.end(), [&fname](const QString &s) {
103 return s.startsWith(fname);
104 });
105 if (it != env.end()) {
106 env.erase(it);
107 if (env.isEmpty()) {
108 env.append(QStringLiteral(DUMMYENV));
109 }
110 setEnvironment(env);
111 }
112}
113
114void KProcess::setProgram(const QString &exe, const QStringList &args)
115{
118#ifdef Q_OS_WIN
120#endif
121}
122
124{
125 if (argv.isEmpty()) {
126 qCWarning(KCOREADDONS_DEBUG) << "KProcess::setProgram(const QStringList &argv) called on an empty string list, no process will be started.";
127 clearProgram();
128 return;
129 }
130
131 QStringList args = argv;
134#ifdef Q_OS_WIN
136#endif
137}
138
140{
141 if (QProcess::program().isEmpty()) {
143 } else {
144 setArguments(arguments() << arg);
145 }
146 return *this;
147}
148
150{
151 if (QProcess::program().isEmpty()) {
152 setProgram(args);
153 } else {
154 setArguments(arguments() << args);
155 }
156 return *this;
157}
158
160{
163#ifdef Q_OS_WIN
165#endif
166}
167
168// #ifdef NON_FREE // ... as they ship non-POSIX /bin/sh
169#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) && !defined(__GNU__) \
170 && !defined(__APPLE__)
171const static bool s_nonFreeUnix = true;
172#else
173const static bool s_nonFreeUnix = false;
174#endif
175
177{
180 if (err == KShell::NoError && !args.isEmpty()) {
182 if (!QProcess::program().isEmpty()) {
183 setArguments(args);
184#ifdef Q_OS_WIN
186#endif
187 return;
188 }
189 }
190
191 setArguments({});
192
193#ifdef Q_OS_UNIX
194 if (s_nonFreeUnix) {
195 // If /bin/sh is a symlink, we can be pretty sure that it points to a
196 // POSIX shell - the original bourne shell is about the only non-POSIX
197 // shell still in use and it is always installed natively as /bin/sh.
198 QString shell = QFile::symLinkTarget(QStringLiteral("/bin/sh"));
199 if (shell.isEmpty()) {
200 // Try some known POSIX shells.
201 static const char *s_knownShells[] = {"ksh", "ash", "bash", "zsh"};
202 for (const auto str : s_knownShells) {
204 if (!shell.isEmpty()) {
205 break;
206 }
207 }
208 }
209 if (shell.isEmpty()) { // We're pretty much screwed, to be honest ...
210 shell = QStringLiteral("/bin/sh");
211 }
213 } else {
214 QProcess::setProgram((QStringLiteral("/bin/sh")));
215 }
216
217 setArguments(arguments() << 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 QProcess::setProgram(QString::fromUtf16((const char16_t *)sysdir, size) + QLatin1String("\\cmd.exe"));
227 setNativeArguments(QLatin1String("/V:OFF /S /C \"") + cmd + QLatin1Char('"'));
228#else
229 QProcess::setProgram(QStringLiteral("\\windows\\cmd.exe"));
230 setNativeArguments(QStringLiteral("/S /C \"") + cmd + QLatin1Char('"'));
231#endif
232#endif
233}
234
236{
237 QStringList argv = arguments();
239 return argv;
240}
241
243{
244 Q_D(KProcess);
245
246 QProcess::start(d->openMode);
247}
248
249int 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
261int 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
269int KProcess::execute(const QStringList &argv, int msecs)
270{
271 KProcess p;
272 p.setProgram(argv);
273 return p.execute(msecs);
274}
275
277{
278 qint64 pid;
280 return 0;
281 }
282 return static_cast<int>(pid);
283}
284
285// static
286int KProcess::startDetached(const QString &exe, const QStringList &args)
287{
288 qint64 pid;
289 if (!QProcess::startDetached(exe, args, QString(), &pid)) {
290 return 0;
291 }
292 return static_cast<int>(pid);
293}
294
295// static
297{
298 if (argv.isEmpty()) {
299 qCWarning(KCOREADDONS_DEBUG) << "KProcess::startDetached(const QStringList &argv) called on an empty string list, no process will be started.";
300 return 0;
301 }
302
303 QStringList args = argv;
304 QString prog = args.takeFirst();
305 return startDetached(prog, args);
306}
307
308#include "moc_kprocess.cpp"
Child process invocation, monitoring and control.
Definition kprocess.h:34
void start()
Start the process.
Definition kprocess.cpp:242
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:176
void setNextOpenMode(QIODevice::OpenMode mode)
Set the QIODevice open mode the process will be opened in.
Definition kprocess.cpp:54
void clearProgram()
Clear the program and command line argument list.
Definition kprocess.cpp:159
OutputChannelMode
Modes in which the output channels can be opened.
Definition kprocess.h:42
@ ForwardedChannels
Both standard output and standard error are forwarded to the parent process' respective channel.
Definition kprocess.h:49
void unsetEnv(const QString &name)
Removes the variable name from the process' environment.
Definition kprocess.cpp:92
KProcess & operator<<(const QString &arg)
Append an element to the command line argument list for this process.
Definition kprocess.cpp:139
OutputChannelMode outputChannelMode() const
Query how the output channels of the child process are handled.
Definition kprocess.cpp:49
QStringList program() const
Obtain the currently set program and arguments.
Definition kprocess.cpp:235
int startDetached()
Start the process and detach from it.
Definition kprocess.cpp:276
void setOutputChannelMode(OutputChannelMode mode)
Set how to handle the output channels of the child process.
Definition kprocess.cpp:44
void clearEnvironment()
Empties the process' environment.
Definition kprocess.cpp:63
~KProcess() override
Destructor.
void setEnv(const QString &name, const QString &value, bool overwrite=true)
Adds the variable name to the process' environment.
Definition kprocess.cpp:68
std::unique_ptr< KProcessPrivate > const d_ptr
Definition kprocess.h:304
KProcess(QObject *parent=nullptr)
Constructor.
Definition kprocess.cpp:27
int execute(int msecs=-1)
Start the process, wait for it to finish, and return the exit code.
Definition kprocess.cpp:249
void setProgram(const QString &exe, const QStringList &args=QStringList())
Set the program and the command line arguments.
Definition kprocess.cpp:114
KCOREADDONS_EXPORT QStringList splitArgs(const QString &cmd, Options flags=NoOptions, Errors *err=nullptr)
Splits cmd according to system shell word splitting and quoting rules.
@ TildeExpand
Perform tilde expansion.
Definition kshell.h:36
@ AbortOnMeta
Put the parser into full shell mode and bail out if a too complex construct is encountered.
Definition kshell.h:67
Errors
Status codes from splitArgs()
Definition kshell.h:78
@ NoError
Success.
Definition kshell.h:82
QString symLinkTarget() const const
virtual qint64 size() const const
void append(QList< T > &&value)
iterator begin()
iterator end()
iterator erase(const_iterator begin, const_iterator end)
bool isEmpty() const const
void prepend(parameter_type value)
qsizetype removeAll(const AT &t)
value_type takeFirst()
QStringList environment() const const
void setEnvironment(const QStringList &environment)
QStringList arguments() const const
int exitCode() const const
QProcess::ExitStatus exitStatus() const const
void kill()
ProcessChannelMode processChannelMode() const const
QString program() const const
void setArguments(const QStringList &arguments)
void setNativeArguments(const QString &arguments)
void setProcessChannelMode(ProcessChannelMode mode)
void setProgram(const QString &program)
void start(OpenMode mode)
bool startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid)
QStringList systemEnvironment()
bool waitForFinished(int msecs)
QString workingDirectory() const const
QString findExecutable(const QString &executableName, const QStringList &paths)
QString & append(QChar ch)
QString fromUtf16(const char16_t *unicode, qsizetype size)
bool isEmpty() const const
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Nov 1 2024 18:53:59 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.