KDECore
kprocess.cpp
Go to the documentation of this file.
00001 /* 00002 This file is part of the KDE libraries 00003 00004 Copyright (C) 2007 Oswald Buddenhagen <ossi@kde.org> 00005 00006 This library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU Library General Public 00008 License as published by the Free Software Foundation; either 00009 version 2 of the License, or (at your option) any later version. 00010 00011 This library is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 Library General Public License for more details. 00015 00016 You should have received a copy of the GNU Library General Public License 00017 along with this library; see the file COPYING.LIB. If not, write to 00018 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00019 Boston, MA 02110-1301, USA. 00020 */ 00021 00022 #include "kprocess_p.h" 00023 00024 #include <kstandarddirs.h> 00025 #include <kshell.h> 00026 #ifdef Q_OS_WIN 00027 # include <kshell_p.h> 00028 #endif 00029 00030 #include <qfile.h> 00031 00032 #ifdef Q_OS_WIN 00033 # include <windows.h> 00034 #else 00035 # include <unistd.h> 00036 # include <errno.h> 00037 #endif 00038 00039 #ifndef Q_OS_WIN 00040 # define STD_OUTPUT_HANDLE 1 00041 # define STD_ERROR_HANDLE 2 00042 #endif 00043 00044 #ifdef _WIN32_WCE 00045 #include <stdio.h> 00046 #endif 00047 00048 void KProcessPrivate::writeAll(const QByteArray &buf, int fd) 00049 { 00050 #ifdef Q_OS_WIN 00051 #ifndef _WIN32_WCE 00052 HANDLE h = GetStdHandle(fd); 00053 if (h) { 00054 DWORD wr; 00055 WriteFile(h, buf.data(), buf.size(), &wr, 0); 00056 } 00057 #else 00058 fwrite(buf.data(), 1, buf.size(), (FILE*)fd); 00059 #endif 00060 #else 00061 int off = 0; 00062 do { 00063 int ret = ::write(fd, buf.data() + off, buf.size() - off); 00064 if (ret < 0) { 00065 if (errno != EINTR) 00066 return; 00067 } else { 00068 off += ret; 00069 } 00070 } while (off < buf.size()); 00071 #endif 00072 } 00073 00074 void KProcessPrivate::forwardStd(KProcess::ProcessChannel good, int fd) 00075 { 00076 Q_Q(KProcess); 00077 00078 QProcess::ProcessChannel oc = q->readChannel(); 00079 q->setReadChannel(good); 00080 writeAll(q->readAll(), fd); 00081 q->setReadChannel(oc); 00082 } 00083 00084 void KProcessPrivate::_k_forwardStdout() 00085 { 00086 #ifndef _WIN32_WCE 00087 forwardStd(KProcess::StandardOutput, STD_OUTPUT_HANDLE); 00088 #else 00089 forwardStd(KProcess::StandardOutput, (int)stdout); 00090 #endif 00091 } 00092 00093 void KProcessPrivate::_k_forwardStderr() 00094 { 00095 #ifndef _WIN32_WCE 00096 forwardStd(KProcess::StandardError, STD_ERROR_HANDLE); 00097 #else 00098 forwardStd(KProcess::StandardError, (int)stderr); 00099 #endif 00100 } 00101 00103 // public member functions // 00105 00106 KProcess::KProcess(QObject *parent) : 00107 QProcess(parent), 00108 d_ptr(new KProcessPrivate) 00109 { 00110 d_ptr->q_ptr = this; 00111 setOutputChannelMode(ForwardedChannels); 00112 } 00113 00114 KProcess::KProcess(KProcessPrivate *d, QObject *parent) : 00115 QProcess(parent), 00116 d_ptr(d) 00117 { 00118 d_ptr->q_ptr = this; 00119 setOutputChannelMode(ForwardedChannels); 00120 } 00121 00122 KProcess::~KProcess() 00123 { 00124 delete d_ptr; 00125 } 00126 00127 void KProcess::setOutputChannelMode(OutputChannelMode mode) 00128 { 00129 Q_D(KProcess); 00130 00131 d->outputChannelMode = mode; 00132 disconnect(this, SIGNAL(readyReadStandardOutput())); 00133 disconnect(this, SIGNAL(readyReadStandardError())); 00134 switch (mode) { 00135 case OnlyStdoutChannel: 00136 connect(this, SIGNAL(readyReadStandardError()), SLOT(_k_forwardStderr())); 00137 break; 00138 case OnlyStderrChannel: 00139 connect(this, SIGNAL(readyReadStandardOutput()), SLOT(_k_forwardStdout())); 00140 break; 00141 default: 00142 QProcess::setProcessChannelMode((ProcessChannelMode)mode); 00143 return; 00144 } 00145 QProcess::setProcessChannelMode(QProcess::SeparateChannels); 00146 } 00147 00148 KProcess::OutputChannelMode KProcess::outputChannelMode() const 00149 { 00150 Q_D(const KProcess); 00151 00152 return d->outputChannelMode; 00153 } 00154 00155 void KProcess::setNextOpenMode(QIODevice::OpenMode mode) 00156 { 00157 Q_D(KProcess); 00158 00159 d->openMode = mode; 00160 } 00161 00162 #define DUMMYENV "_KPROCESS_DUMMY_=" 00163 00164 void KProcess::clearEnvironment() 00165 { 00166 setEnvironment(QStringList() << QString::fromLatin1(DUMMYENV)); 00167 } 00168 00169 void KProcess::setEnv(const QString &name, const QString &value, bool overwrite) 00170 { 00171 QStringList env = environment(); 00172 if (env.isEmpty()) { 00173 env = systemEnvironment(); 00174 env.removeAll(QString::fromLatin1(DUMMYENV)); 00175 } 00176 QString fname(name); 00177 fname.append(QLatin1Char('=')); 00178 for (QStringList::Iterator it = env.begin(); it != env.end(); ++it) 00179 if ((*it).startsWith(fname)) { 00180 if (overwrite) { 00181 *it = fname.append(value); 00182 setEnvironment(env); 00183 } 00184 return; 00185 } 00186 env.append(fname.append(value)); 00187 setEnvironment(env); 00188 } 00189 00190 void KProcess::unsetEnv(const QString &name) 00191 { 00192 QStringList env = environment(); 00193 if (env.isEmpty()) { 00194 env = systemEnvironment(); 00195 env.removeAll(QString::fromLatin1(DUMMYENV)); 00196 } 00197 QString fname(name); 00198 fname.append(QLatin1Char('=')); 00199 for (QStringList::Iterator it = env.begin(); it != env.end(); ++it) 00200 if ((*it).startsWith(fname)) { 00201 env.erase(it); 00202 if (env.isEmpty()) 00203 env.append(QString::fromLatin1(DUMMYENV)); 00204 setEnvironment(env); 00205 return; 00206 } 00207 } 00208 00209 void KProcess::setProgram(const QString &exe, const QStringList &args) 00210 { 00211 Q_D(KProcess); 00212 00213 d->prog = exe; 00214 d->args = args; 00215 #ifdef Q_OS_WIN 00216 setNativeArguments(QString()); 00217 #endif 00218 } 00219 00220 void KProcess::setProgram(const QStringList &argv) 00221 { 00222 Q_D(KProcess); 00223 00224 Q_ASSERT( !argv.isEmpty() ); 00225 d->args = argv; 00226 d->prog = d->args.takeFirst(); 00227 #ifdef Q_OS_WIN 00228 setNativeArguments(QString()); 00229 #endif 00230 } 00231 00232 KProcess &KProcess::operator<<(const QString &arg) 00233 { 00234 Q_D(KProcess); 00235 00236 if (d->prog.isEmpty()) 00237 d->prog = arg; 00238 else 00239 d->args << arg; 00240 return *this; 00241 } 00242 00243 KProcess &KProcess::operator<<(const QStringList &args) 00244 { 00245 Q_D(KProcess); 00246 00247 if (d->prog.isEmpty()) 00248 setProgram(args); 00249 else 00250 d->args << args; 00251 return *this; 00252 } 00253 00254 void KProcess::clearProgram() 00255 { 00256 Q_D(KProcess); 00257 00258 d->prog.clear(); 00259 d->args.clear(); 00260 #ifdef Q_OS_WIN 00261 setNativeArguments(QString()); 00262 #endif 00263 } 00264 00265 void KProcess::setShellCommand(const QString &cmd) 00266 { 00267 Q_D(KProcess); 00268 00269 KShell::Errors err; 00270 d->args = KShell::splitArgs( 00271 cmd, KShell::AbortOnMeta | KShell::TildeExpand, &err); 00272 if (err == KShell::NoError && !d->args.isEmpty()) { 00273 d->prog = KStandardDirs::findExe(d->args[0]); 00274 if (!d->prog.isEmpty()) { 00275 d->args.removeFirst(); 00276 #ifdef Q_OS_WIN 00277 setNativeArguments(QString()); 00278 #endif 00279 return; 00280 } 00281 } 00282 00283 d->args.clear(); 00284 00285 #ifdef Q_OS_UNIX 00286 // #ifdef NON_FREE // ... as they ship non-POSIX /bin/sh 00287 # if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) && !defined(__GNU__) 00288 // If /bin/sh is a symlink, we can be pretty sure that it points to a 00289 // POSIX shell - the original bourne shell is about the only non-POSIX 00290 // shell still in use and it is always installed natively as /bin/sh. 00291 d->prog = QFile::symLinkTarget(QString::fromLatin1("/bin/sh")); 00292 if (d->prog.isEmpty()) { 00293 // Try some known POSIX shells. 00294 d->prog = KStandardDirs::findExe(QString::fromLatin1("ksh")); 00295 if (d->prog.isEmpty()) { 00296 d->prog = KStandardDirs::findExe(QString::fromLatin1("ash")); 00297 if (d->prog.isEmpty()) { 00298 d->prog = KStandardDirs::findExe(QString::fromLatin1("bash")); 00299 if (d->prog.isEmpty()) { 00300 d->prog = KStandardDirs::findExe(QString::fromLatin1("zsh")); 00301 if (d->prog.isEmpty()) 00302 // We're pretty much screwed, to be honest ... 00303 d->prog = QString::fromLatin1("/bin/sh"); 00304 } 00305 } 00306 } 00307 } 00308 # else 00309 d->prog = QString::fromLatin1("/bin/sh"); 00310 # endif 00311 00312 d->args << QString::fromLatin1("-c") << cmd; 00313 #else // Q_OS_UNIX 00314 // KMacroExpander::expandMacrosShellQuote(), KShell::quoteArg() and 00315 // KShell::joinArgs() may generate these for security reasons. 00316 setEnv(PERCENT_VARIABLE, QLatin1String("%")); 00317 00318 #ifndef _WIN32_WCE 00319 WCHAR sysdir[MAX_PATH + 1]; 00320 UINT size = GetSystemDirectoryW(sysdir, MAX_PATH + 1); 00321 d->prog = QString::fromUtf16((const ushort *) sysdir, size); 00322 d->prog += QLatin1String("\\cmd.exe"); 00323 setNativeArguments(QLatin1String("/V:OFF /S /C \"") + cmd + QLatin1Char('"')); 00324 #else 00325 d->prog = QLatin1String("\\windows\\cmd.exe"); 00326 setNativeArguments(QLatin1String("/S /C \"") + cmd + QLatin1Char('"')); 00327 #endif 00328 #endif 00329 } 00330 00331 QStringList KProcess::program() const 00332 { 00333 Q_D(const KProcess); 00334 00335 QStringList argv = d->args; 00336 argv.prepend(d->prog); 00337 return argv; 00338 } 00339 00340 void KProcess::start() 00341 { 00342 Q_D(KProcess); 00343 00344 QProcess::start(d->prog, d->args, d->openMode); 00345 } 00346 00347 int KProcess::execute(int msecs) 00348 { 00349 start(); 00350 if (!waitForFinished(msecs)) { 00351 kill(); 00352 waitForFinished(-1); 00353 return -2; 00354 } 00355 return (exitStatus() == QProcess::NormalExit) ? exitCode() : -1; 00356 } 00357 00358 // static 00359 int KProcess::execute(const QString &exe, const QStringList &args, int msecs) 00360 { 00361 KProcess p; 00362 p.setProgram(exe, args); 00363 return p.execute(msecs); 00364 } 00365 00366 // static 00367 int KProcess::execute(const QStringList &argv, int msecs) 00368 { 00369 KProcess p; 00370 p.setProgram(argv); 00371 return p.execute(msecs); 00372 } 00373 00374 int KProcess::startDetached() 00375 { 00376 Q_D(KProcess); 00377 00378 qint64 pid; 00379 if (!QProcess::startDetached(d->prog, d->args, workingDirectory(), &pid)) 00380 return 0; 00381 return (int) pid; 00382 } 00383 00384 // static 00385 int KProcess::startDetached(const QString &exe, const QStringList &args) 00386 { 00387 qint64 pid; 00388 if (!QProcess::startDetached(exe, args, QString(), &pid)) 00389 return 0; 00390 return (int) pid; 00391 } 00392 00393 // static 00394 int KProcess::startDetached(const QStringList &argv) 00395 { 00396 QStringList args = argv; 00397 QString prog = args.takeFirst(); 00398 return startDetached(prog, args); 00399 } 00400 00401 int KProcess::pid() const 00402 { 00403 #ifdef Q_OS_UNIX 00404 return (int) QProcess::pid(); 00405 #else 00406 return QProcess::pid() ? QProcess::pid()->dwProcessId : 0; 00407 #endif 00408 } 00409 00410 #include "kprocess.moc"
KDE 4.6 API Reference