File indexing completed on 2025-01-19 04:23:27
0001 /* 0002 * This file is a part of QTerminal - http://gitorious.org/qterminal 0003 * 0004 * This file was un-linked from KDE and modified 0005 * by Maxim Bourmistrov <maxim@unixconn.com> 0006 * 0007 */ 0008 0009 /* 0010 This file is part of the KDE libraries 0011 0012 Copyright (C) 2007 Oswald Buddenhagen <ossi@kde.org> 0013 0014 This library is free software; you can redistribute it and/or 0015 modify it under the terms of the GNU Library General Public 0016 License as published by the Free Software Foundation; either 0017 version 2 of the License, or (at your option) any later version. 0018 0019 This library is distributed in the hope that it will be useful, 0020 but WITHOUT ANY WARRANTY; without even the implied warranty of 0021 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0022 Library General Public License for more details. 0023 0024 You should have received a copy of the GNU Library General Public License 0025 along with this library; see the file COPYING.LIB. If not, write to 0026 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0027 Boston, MA 02110-1301, USA. 0028 */ 0029 0030 #include "kprocess.h" 0031 0032 #include <qfile.h> 0033 0034 #ifdef Q_OS_WIN 0035 # include <windows.h> 0036 #else 0037 # include <unistd.h> 0038 # include <errno.h> 0039 #endif 0040 0041 #ifndef Q_OS_WIN 0042 # define STD_OUTPUT_HANDLE 1 0043 # define STD_ERROR_HANDLE 2 0044 #endif 0045 0046 #ifdef _WIN32_WCE 0047 #include <stdio.h> 0048 #endif 0049 0050 void KProcessPrivate::writeAll(const QByteArray &buf, int fd) 0051 { 0052 #ifdef Q_OS_WIN 0053 #ifndef _WIN32_WCE 0054 HANDLE h = GetStdHandle(fd); 0055 if (h) { 0056 DWORD wr; 0057 WriteFile(h, buf.data(), buf.size(), &wr, 0); 0058 } 0059 #else 0060 fwrite(buf.data(), 1, buf.size(), (FILE*)fd); 0061 #endif 0062 #else 0063 int off = 0; 0064 do { 0065 int ret = ::write(fd, buf.data() + off, buf.size() - off); 0066 if (ret < 0) { 0067 if (errno != EINTR) 0068 return; 0069 } else { 0070 off += ret; 0071 } 0072 } while (off < buf.size()); 0073 #endif 0074 } 0075 0076 void KProcessPrivate::forwardStd(KProcess::ProcessChannel good, int fd) 0077 { 0078 Q_Q(KProcess); 0079 0080 QProcess::ProcessChannel oc = q->readChannel(); 0081 q->setReadChannel(good); 0082 writeAll(q->readAll(), fd); 0083 q->setReadChannel(oc); 0084 } 0085 0086 void KProcessPrivate::_k_forwardStdout() 0087 { 0088 #ifndef _WIN32_WCE 0089 forwardStd(KProcess::StandardOutput, STD_OUTPUT_HANDLE); 0090 #else 0091 forwardStd(KProcess::StandardOutput, (int)stdout); 0092 #endif 0093 } 0094 0095 void KProcessPrivate::_k_forwardStderr() 0096 { 0097 #ifndef _WIN32_WCE 0098 forwardStd(KProcess::StandardError, STD_ERROR_HANDLE); 0099 #else 0100 forwardStd(KProcess::StandardError, (int)stderr); 0101 #endif 0102 } 0103 0104 ///////////////////////////// 0105 // public member functions // 0106 ///////////////////////////// 0107 0108 KProcess::KProcess(QObject *parent) : 0109 QProcess(parent), 0110 d_ptr(new KProcessPrivate) 0111 { 0112 d_ptr->q_ptr = this; 0113 setOutputChannelMode(ForwardedChannels); 0114 } 0115 0116 KProcess::KProcess(KProcessPrivate *d, QObject *parent) : 0117 QProcess(parent), 0118 d_ptr(d) 0119 { 0120 d_ptr->q_ptr = this; 0121 setOutputChannelMode(ForwardedChannels); 0122 } 0123 0124 KProcess::~KProcess() 0125 { 0126 delete d_ptr; 0127 } 0128 0129 void KProcess::setOutputChannelMode(OutputChannelMode mode) 0130 { 0131 Q_D(KProcess); 0132 0133 d->outputChannelMode = mode; 0134 disconnect(this, SIGNAL(readyReadStandardOutput())); 0135 disconnect(this, SIGNAL(readyReadStandardError())); 0136 switch (mode) { 0137 case OnlyStdoutChannel: 0138 connect(this, SIGNAL(readyReadStandardError()), SLOT(_k_forwardStderr())); 0139 break; 0140 case OnlyStderrChannel: 0141 connect(this, SIGNAL(readyReadStandardOutput()), SLOT(_k_forwardStdout())); 0142 break; 0143 default: 0144 QProcess::setProcessChannelMode((ProcessChannelMode)mode); 0145 return; 0146 } 0147 QProcess::setProcessChannelMode(QProcess::SeparateChannels); 0148 } 0149 0150 KProcess::OutputChannelMode KProcess::outputChannelMode() const 0151 { 0152 Q_D(const KProcess); 0153 0154 return d->outputChannelMode; 0155 } 0156 0157 void KProcess::setNextOpenMode(QIODevice::OpenMode mode) 0158 { 0159 Q_D(KProcess); 0160 0161 d->openMode = mode; 0162 } 0163 0164 #define DUMMYENV "_KPROCESS_DUMMY_=" 0165 0166 void KProcess::clearEnvironment() 0167 { 0168 setEnvironment(QStringList() << QString::fromLatin1(DUMMYENV)); 0169 } 0170 0171 void KProcess::setEnv(const QString &name, const QString &value, bool overwrite) 0172 { 0173 QStringList env = environment(); 0174 if (env.isEmpty()) { 0175 env = systemEnvironment(); 0176 env.removeAll(QString::fromLatin1(DUMMYENV)); 0177 } 0178 QString fname(name); 0179 fname.append(QLatin1Char('=')); 0180 for (QStringList::Iterator it = env.begin(); it != env.end(); ++it) 0181 if ((*it).startsWith(fname)) { 0182 if (overwrite) { 0183 *it = fname.append(value); 0184 setEnvironment(env); 0185 } 0186 return; 0187 } 0188 env.append(fname.append(value)); 0189 setEnvironment(env); 0190 } 0191 0192 void KProcess::unsetEnv(const QString &name) 0193 { 0194 QStringList env = environment(); 0195 if (env.isEmpty()) { 0196 env = systemEnvironment(); 0197 env.removeAll(QString::fromLatin1(DUMMYENV)); 0198 } 0199 QString fname(name); 0200 fname.append(QLatin1Char('=')); 0201 for (QStringList::Iterator it = env.begin(); it != env.end(); ++it) 0202 if ((*it).startsWith(fname)) { 0203 env.erase(it); 0204 if (env.isEmpty()) 0205 env.append(QString::fromLatin1(DUMMYENV)); 0206 setEnvironment(env); 0207 return; 0208 } 0209 } 0210 0211 void KProcess::setProgram(const QString &exe, const QStringList &args) 0212 { 0213 Q_D(KProcess); 0214 0215 d->prog = exe; 0216 d->args = args; 0217 #ifdef Q_OS_WIN 0218 setNativeArguments(QString()); 0219 #endif 0220 } 0221 0222 void KProcess::setProgram(const QStringList &argv) 0223 { 0224 Q_D(KProcess); 0225 0226 Q_ASSERT( !argv.isEmpty() ); 0227 d->args = argv; 0228 d->prog = d->args.takeFirst(); 0229 #ifdef Q_OS_WIN 0230 setNativeArguments(QString()); 0231 #endif 0232 } 0233 0234 KProcess &KProcess::operator<<(const QString &arg) 0235 { 0236 Q_D(KProcess); 0237 0238 if (d->prog.isEmpty()) 0239 d->prog = arg; 0240 else 0241 d->args << arg; 0242 return *this; 0243 } 0244 0245 KProcess &KProcess::operator<<(const QStringList &args) 0246 { 0247 Q_D(KProcess); 0248 0249 if (d->prog.isEmpty()) 0250 setProgram(args); 0251 else 0252 d->args << args; 0253 return *this; 0254 } 0255 0256 void KProcess::clearProgram() 0257 { 0258 Q_D(KProcess); 0259 0260 d->prog.clear(); 0261 d->args.clear(); 0262 #ifdef Q_OS_WIN 0263 setNativeArguments(QString()); 0264 #endif 0265 } 0266 0267 #if 0 0268 void KProcess::setShellCommand(const QString &cmd) 0269 { 0270 Q_D(KProcess); 0271 0272 KShell::Errors err; 0273 d->args = KShell::splitArgs( 0274 cmd, KShell::AbortOnMeta | KShell::TildeExpand, &err); 0275 if (err == KShell::NoError && !d->args.isEmpty()) { 0276 d->prog = KStandardDirs::findExe(d->args[0]); 0277 if (!d->prog.isEmpty()) { 0278 d->args.removeFirst(); 0279 #ifdef Q_OS_WIN 0280 setNativeArguments(QString()); 0281 #endif 0282 return; 0283 } 0284 } 0285 0286 d->args.clear(); 0287 0288 #ifdef Q_OS_UNIX 0289 // #ifdef NON_FREE // ... as they ship non-POSIX /bin/sh 0290 # if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) && !defined(__GNU__) 0291 // If /bin/sh is a symlink, we can be pretty sure that it points to a 0292 // POSIX shell - the original bourne shell is about the only non-POSIX 0293 // shell still in use and it is always installed natively as /bin/sh. 0294 d->prog = QFile::symLinkTarget(QString::fromLatin1("/bin/sh")); 0295 if (d->prog.isEmpty()) { 0296 // Try some known POSIX shells. 0297 d->prog = KStandardDirs::findExe(QString::fromLatin1("ksh")); 0298 if (d->prog.isEmpty()) { 0299 d->prog = KStandardDirs::findExe(QString::fromLatin1("ash")); 0300 if (d->prog.isEmpty()) { 0301 d->prog = KStandardDirs::findExe(QString::fromLatin1("bash")); 0302 if (d->prog.isEmpty()) { 0303 d->prog = KStandardDirs::findExe(QString::fromLatin1("zsh")); 0304 if (d->prog.isEmpty()) 0305 // We're pretty much screwed, to be honest ... 0306 d->prog = QString::fromLatin1("/bin/sh"); 0307 } 0308 } 0309 } 0310 } 0311 # else 0312 d->prog = QString::fromLatin1("/bin/sh"); 0313 # endif 0314 0315 d->args << QString::fromLatin1("-c") << cmd; 0316 #else // Q_OS_UNIX 0317 // KMacroExpander::expandMacrosShellQuote(), KShell::quoteArg() and 0318 // KShell::joinArgs() may generate these for security reasons. 0319 setEnv(PERCENT_VARIABLE, QLatin1String("%")); 0320 0321 #ifndef _WIN32_WCE 0322 WCHAR sysdir[MAX_PATH + 1]; 0323 UINT size = GetSystemDirectoryW(sysdir, MAX_PATH + 1); 0324 d->prog = QString::fromUtf16((const ushort *) sysdir, size); 0325 d->prog += QLatin1String("\\cmd.exe"); 0326 setNativeArguments(QLatin1String("/V:OFF /S /C \"") + cmd + QLatin1Char('"')); 0327 #else 0328 d->prog = QLatin1String("\\windows\\cmd.exe"); 0329 setNativeArguments(QLatin1String("/S /C \"") + cmd + QLatin1Char('"')); 0330 #endif 0331 #endif 0332 } 0333 #endif 0334 QStringList KProcess::program() const 0335 { 0336 Q_D(const KProcess); 0337 0338 QStringList argv = d->args; 0339 argv.prepend(d->prog); 0340 return argv; 0341 } 0342 0343 void KProcess::start() 0344 { 0345 Q_D(KProcess); 0346 0347 QProcess::start(d->prog, d->args, d->openMode); 0348 } 0349 0350 int KProcess::execute(int msecs) 0351 { 0352 start(); 0353 if (!waitForFinished(msecs)) { 0354 kill(); 0355 waitForFinished(-1); 0356 return -2; 0357 } 0358 return (exitStatus() == QProcess::NormalExit) ? exitCode() : -1; 0359 } 0360 0361 // static 0362 int KProcess::execute(const QString &exe, const QStringList &args, int msecs) 0363 { 0364 KProcess p; 0365 p.setProgram(exe, args); 0366 return p.execute(msecs); 0367 } 0368 0369 // static 0370 int KProcess::execute(const QStringList &argv, int msecs) 0371 { 0372 KProcess p; 0373 p.setProgram(argv); 0374 return p.execute(msecs); 0375 } 0376 0377 int KProcess::startDetached() 0378 { 0379 Q_D(KProcess); 0380 0381 qint64 pid; 0382 if (!QProcess::startDetached(d->prog, d->args, workingDirectory(), &pid)) 0383 return 0; 0384 return (int) pid; 0385 } 0386 0387 // static 0388 int KProcess::startDetached(const QString &exe, const QStringList &args) 0389 { 0390 qint64 pid; 0391 if (!QProcess::startDetached(exe, args, QString(), &pid)) 0392 return 0; 0393 return (int) pid; 0394 } 0395 0396 // static 0397 int KProcess::startDetached(const QStringList &argv) 0398 { 0399 QStringList args = argv; 0400 QString prog = args.takeFirst(); 0401 return startDetached(prog, args); 0402 } 0403 0404 int KProcess::pid() const 0405 { 0406 #ifdef Q_OS_UNIX 0407 return (int) QProcess::processId(); 0408 #else 0409 return QProcess::pid() ? QProcess::pid()->dwProcessId : 0; 0410 #endif 0411 } 0412