| # kdecore Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# kprocess.cpp

    00001 /*
    00002
    00003    $Id: kprocess.cpp 348106 2004-09-21 09:47:32Z ossi $
    00004
    00005    This file is part of the KDE libraries
    00006    Copyright (C) 1997 Christian Czezatke (e9025461@student.tuwien.ac.at)
    00007
    00008    This library is free software; you can redistribute it and/or
    00009    modify it under the terms of the GNU Library General Public
    00010    License as published by the Free Software Foundation; either
    00011    version 2 of the License, or (at your option) any later version.
    00012
    00013    This library is distributed in the hope that it will be useful,
    00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
    00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00016    Library General Public License for more details.
    00017
    00018    You should have received a copy of the GNU Library General Public License
    00019    along with this library; see the file COPYING.LIB.  If not, write to
    00020    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00021    Boston, MA 02111-1307, USA.
    00022 */
    00023
    00024
    00025 #include "kprocess.h"
    00026 #include "kprocctrl.h"
    00027 #include "kpty.h"
    00028
    00029 #include <config.h>
    00030
    00031 #ifdef __sgi
    00032 #define __svr4__
    00033 #endif
    00034
    00035 #ifdef __osf__
    00036 #define _OSF_SOURCE
    00037 #include <float.h>
    00038 #endif
    00039
    00040 #ifdef _AIX
    00041 #define _ALL_SOURCE
    00042 #endif
    00043
    00044 #ifdef Q_OS_UNIX
    00045 #include <sys/socket.h>
    00046 #include <sys/ioctl.h>
    00047 #endif
    00048
    00049 #include <sys/types.h>
    00050 #include <sys/time.h>
    00051 #include <sys/resource.h>
    00052 #include <sys/stat.h>
    00053 #include <sys/wait.h>
    00054
    00055 #ifdef HAVE_SYS_STROPTS_H
    00056 #include <sys/stropts.h>    // Defines I_PUSH
    00057 #define _NEW_TTY_CTRL
    00058 #endif
    00059 #ifdef HAVE_SYS_SELECT_H
    00060 #include <sys/select.h>
    00061 #endif
    00062
    00063 #include <errno.h>
    00064 #include <assert.h>
    00065 #include <fcntl.h>
    00066 #include <time.h>
    00067 #include <stdlib.h>
    00068 #include <signal.h>
    00069 #include <stdio.h>
    00070 #include <string.h>
    00071 #include <unistd.h>
    00072 #include <pwd.h>
    00073 #include <grp.h>
    00074
    00075 #include <qfile.h>
    00076 #include <qsocketnotifier.h>
    00077 #include <qapplication.h>
    00078
    00079 #include <kdebug.h>
    00080 #include <kstandarddirs.h>
    00081 #include <kuser.h>
    00082
    00083
    00085 // private data //
    00087
    00088 class KProcessPrivate {
    00089 public:
    00090    KProcessPrivate() :
    00091      usePty(KProcess::NoCommunication),
    00092      addUtmp(false), useShell(false),
    00093 #ifdef Q_OS_UNIX
    00094      pty(0),
    00095 #endif
    00096      priority(0)
    00097    {
    00098    }
    00099
    00100    KProcess::Communication usePty;
    00101    bool addUtmp : 1;
    00102    bool useShell : 1;
    00103
    00104 #ifdef Q_OS_UNIX
    00105    KPty *pty;
    00106 #endif
    00107
    00108    int priority;
    00109
    00110    QMap<QString,QString> env;
    00111    QString wd;
    00112    QCString shell;
    00113    QCString executable;
    00114 };
    00115
    00117 // public member functions //
    00119
    00120 KProcess::KProcess( QObject* parent, const char *name )
    00121   : QObject( parent, name ),
    00122     run_mode(NotifyOnExit),
    00123     runs(false),
    00124     pid_(0),
    00125     status(0),
    00126     keepPrivs(false),
    00127     innot(0),
    00128     outnot(0),
    00129     errnot(0),
    00130     communication(NoCommunication),
    00131     input_data(0),
    00132     input_sent(0),
    00133     input_total(0)
    00134 {
    00135   KProcessController::ref();
    00136   KProcessController::theKProcessController->addKProcess(this);
    00137
    00138   d = new KProcessPrivate;
    00139
    00140   out[0] = out[1] = -1;
    00141   in[0] = in[1] = -1;
    00142   err[0] = err[1] = -1;
    00143 }
    00144
    00145 KProcess::KProcess()
    00146   : QObject(),
    00147     run_mode(NotifyOnExit),
    00148     runs(false),
    00149     pid_(0),
    00150     status(0),
    00151     keepPrivs(false),
    00152     innot(0),
    00153     outnot(0),
    00154     errnot(0),
    00155     communication(NoCommunication),
    00156     input_data(0),
    00157     input_sent(0),
    00158     input_total(0)
    00159 {
    00160   KProcessController::ref();
    00161   KProcessController::theKProcessController->addKProcess(this);
    00162
    00163   d = new KProcessPrivate;
    00164
    00165   out[0] = out[1] = -1;
    00166   in[0] = in[1] = -1;
    00167   err[0] = err[1] = -1;
    00168 }
    00169
    00170 void
    00171 KProcess::setEnvironment(const QString &name, const QString &value)
    00172 {
    00173    d->env.insert(name, value);
    00174 }
    00175
    00176 void
    00177 KProcess::setWorkingDirectory(const QString &dir)
    00178 {
    00179    d->wd = dir;
    00180 }
    00181
    00182 void
    00183 KProcess::setupEnvironment()
    00184 {
    00185    QMap<QString,QString>::Iterator it;
    00186    for(it = d->env.begin(); it != d->env.end(); ++it)
    00187    {
    00188       setenv(QFile::encodeName(it.key()).data(),
    00189              QFile::encodeName(it.data()).data(), 1);
    00190    }
    00191    if (!d->wd.isEmpty())
    00192    {
    00193       chdir(QFile::encodeName(d->wd).data());
    00194    }
    00195 }
    00196
    00197 void
    00198 KProcess::setRunPrivileged(bool keepPrivileges)
    00199 {
    00200    keepPrivs = keepPrivileges;
    00201 }
    00202
    00203 bool
    00204 KProcess::runPrivileged() const
    00205 {
    00206    return keepPrivs;
    00207 }
    00208
    00209 bool
    00210 KProcess::setPriority(int prio)
    00211 {
    00212 #ifdef Q_OS_UNIX
    00213     if (runs) {
    00214         if (setpriority(PRIO_PROCESS, pid_, prio))
    00215             return false;
    00216     } else {
    00217         if (prio > 19 || prio < (geteuid() ? getpriority(PRIO_PROCESS, 0) : -20))
    00218             return false;
    00219     }
    00220 #endif
    00221     d->priority = prio;
    00222     return true;
    00223 }
    00224
    00225 KProcess::~KProcess()
    00226 {
    00227   if (run_mode != DontCare)
    00228     kill(SIGKILL);
    00229   detach();
    00230
    00231 #ifdef Q_OS_UNIX
    00232   delete d->pty;
    00233 #endif
    00234   delete d;
    00235
    00236   KProcessController::theKProcessController->removeKProcess(this);
    00237   KProcessController::deref();
    00238 }
    00239
    00240 void KProcess::detach()
    00241 {
    00242   if (runs) {
    00243     KProcessController::theKProcessController->addProcess(pid_);
    00244     runs = false;
    00245     pid_ = 0; // close without draining
    00246     commClose(); // Clean up open fd's and socket notifiers.
    00247   }
    00248 }
    00249
    00250 void KProcess::setBinaryExecutable(const char *filename)
    00251 {
    00252    d->executable = filename;
    00253 }
    00254
    00255 bool KProcess::setExecutable(const QString& proc)
    00256 {
    00257   if (runs) return false;
    00258
    00259   if (proc.isEmpty())  return false;
    00260
    00261   if (!arguments.isEmpty())
    00262      arguments.remove(arguments.begin());
    00263   arguments.prepend(QFile::encodeName(proc));
    00264
    00265   return true;
    00266 }
    00267
    00268 KProcess &KProcess::operator<<(const QStringList& args)
    00269 {
    00270   QStringList::ConstIterator it = args.begin();
    00271   for ( ; it != args.end() ; ++it )
    00272       arguments.append(QFile::encodeName(*it));
    00273   return *this;
    00274 }
    00275
    00276 KProcess &KProcess::operator<<(const QCString& arg)
    00277 {
    00278   return operator<< (arg.data());
    00279 }
    00280
    00281 KProcess &KProcess::operator<<(const char* arg)
    00282 {
    00283   arguments.append(arg);
    00284   return *this;
    00285 }
    00286
    00287 KProcess &KProcess::operator<<(const QString& arg)
    00288 {
    00289   arguments.append(QFile::encodeName(arg));
    00290   return *this;
    00291 }
    00292
    00293 void KProcess::clearArguments()
    00294 {
    00295   arguments.clear();
    00296 }
    00297
    00298 bool KProcess::start(RunMode runmode, Communication comm)
    00299 {
    00300   if (runs) {
    00301     kdDebug(175) << "Attempted to start an already running process" << endl;
    00302     return false;
    00303   }
    00304
    00305   uint n = arguments.count();
    00306   if (n == 0) {
    00307     kdDebug(175) << "Attempted to start a process without arguments" << endl;
    00308     return false;
    00309   }
    00310 #ifdef Q_OS_UNIX
    00311   char **arglist;
    00312   QCString shellCmd;
    00313   if (d->useShell)
    00314   {
    00315       if (d->shell.isEmpty()) {
    00316         kdDebug(175) << "Invalid shell specified" << endl;
    00317         return false;
    00318       }
    00319
    00320       for (uint i = 0; i < n; i++) {
    00321           shellCmd += arguments[i];
    00322           shellCmd += " "; // CC: to separate the arguments
    00323       }
    00324
    00325       arglist = static_cast<char **>(malloc( 4 * sizeof(char *)));
    00326       arglist[0] = d->shell.data();
    00327       arglist[1] = (char *) "-c";
    00328       arglist[2] = shellCmd.data();
    00329       arglist[3] = 0;
    00330   }
    00331   else
    00332   {
    00333       arglist = static_cast<char **>(malloc( (n + 1) * sizeof(char *)));
    00334       for (uint i = 0; i < n; i++)
    00335          arglist[i] = arguments[i].data();
    00336       arglist[n] = 0;
    00337   }
    00338
    00339   run_mode = runmode;
    00340
    00341   if (!setupCommunication(comm))
    00342   {
    00343       kdDebug(175) << "Could not setup Communication!" << endl;
    00344       free(arglist);
    00345       return false;
    00346   }
    00347
    00348   // We do this in the parent because if we do it in the child process
    00349   // gdb gets confused when the application runs from gdb.
    00350 #ifdef HAVE_INITGROUPS
    00351   struct passwd *pw = geteuid() ? 0 : getpwuid(getuid());
    00352 #endif
    00353
    00354   int fd[2];
    00355   if (pipe(fd))
    00356      fd[0] = fd[1] = -1; // Pipe failed.. continue
    00357
    00358   QApplication::flushX();
    00359
    00360   // we don't use vfork() because
    00361   // - it has unclear semantics and is not standardized
    00362   // - we do way too much magic in the child
    00363   pid_ = fork();
    00364   if (pid_ == 0) {
    00365         // The child process
    00366
    00367         close(fd[0]);
    00368         // Closing of fd[1] indicates that the execvp() succeeded!
    00369         fcntl(fd[1], F_SETFD, FD_CLOEXEC);
    00370
    00371         if (!commSetupDoneC())
    00372           kdDebug(175) << "Could not finish comm setup in child!" << endl;
    00373
    00374         // reset all signal handlers
    00375         struct sigaction act;
    00376         sigemptyset(&act.sa_mask);
    00377         act.sa_handler = SIG_DFL;
    00378         act.sa_flags = 0;
    00379         for (int sig = 1; sig < NSIG; sig++)
    00380           sigaction(sig, &act, 0L);
    00381
    00382         if (d->priority)
    00383             setpriority(PRIO_PROCESS, 0, d->priority);
    00384
    00385         if (!runPrivileged())
    00386         {
    00387            setgid(getgid());
    00388 #ifdef HAVE_INITGROUPS
    00389            if (pw)
    00390               initgroups(pw->pw_name, pw->pw_gid);
    00391 #endif
    00392            setuid(getuid());
    00393         }
    00394
    00395         setupEnvironment();
    00396
    00397         if (runmode == DontCare || runmode == OwnGroup)
    00398           setsid();
    00399
    00400         const char *executable = arglist[0];
    00401         if (!d->executable.isEmpty())
    00402            executable = d->executable.data();
    00403         execvp(executable, arglist);
    00404
    00405         char resultByte = 1;
    00406         write(fd[1], &resultByte, 1);
    00407         _exit(-1);
    00408   } else if (pid_ == -1) {
    00409         // forking failed
    00410
    00411         // commAbort();
    00412         pid_ = 0;
    00413         free(arglist);
    00414         return false;
    00415   }
    00416   // the parent continues here
    00417   free(arglist);
    00418
    00419   if (!commSetupDoneP())
    00420     kdDebug(175) << "Could not finish comm setup in parent!" << endl;
    00421
    00422   // Check whether client could be started.
    00423   close(fd[1]);
    00424   for(;;)
    00425   {
    00426      char resultByte;
    00427      int n = ::read(fd[0], &resultByte, 1);
    00428      if (n == 1)
    00429      {
    00430          // exec() failed
    00431          close(fd[0]);
    00432          waitpid(pid_, 0, 0);
    00433          pid_ = 0;
    00434          commClose();
    00435          return false;
    00436      }
    00437      if (n == -1)
    00438      {
    00439         if (errno == EINTR)
    00440            continue; // Ignore
    00441      }
    00442      break; // success
    00443   }
    00444   close(fd[0]);
    00445
    00446   runs = true;
    00447   switch (runmode)
    00448   {
    00449   case Block:
    00450     for (;;)
    00451     {
    00452       commClose(); // drain only, unless obsolete reimplementation
    00453       if (!runs)
    00454       {
    00455         // commClose detected data on the process exit notifification pipe
    00456         KProcessController::theKProcessController->unscheduleCheck();
    00457         if (waitpid(pid_, &status, WNOHANG) != 0) // error finishes, too
    00458         {
    00459           commClose(); // this time for real (runs is false)
    00460           KProcessController::theKProcessController->rescheduleCheck();
    00461           break;
    00462         }
    00463         runs = true; // for next commClose() iteration
    00464       }
    00465       else
    00466       {
    00467         // commClose is an obsolete reimplementation and waited until
    00468         // all output channels were closed (or it was interrupted).
    00469         // there is a chance that it never gets here ...
    00470         waitpid(pid_, &status, 0);
    00471         runs = false;
    00472         break;
    00473       }
    00474     }
    00475     // why do we do this? i think this signal should be emitted _only_
    00476     // after the process has successfully run _asynchronously_ --ossi
    00477     emit processExited(this);
    00478     break;
    00479   default: // NotifyOnExit & OwnGroup
    00480     input_data = 0; // Discard any data for stdin that might still be there
    00481     break;
    00482   }
    00483   return true;
    00484 #else
    00485   //TODO
    00486   return false;
    00487 #endif
    00488 }
    00489
    00490
    00491
    00492 bool KProcess::kill(int signo)
    00493 {
    00494 #ifdef Q_OS_UNIX
    00495   if (runs && pid_ > 0 && !::kill(run_mode == OwnGroup ? -pid_ : pid_, signo))
    00496     return true;
    00497 #endif
    00498   return false;
    00499 }
    00500
    00501
    00502
    00503 bool KProcess::isRunning() const
    00504 {
    00505   return runs;
    00506 }
    00507
    00508
    00509
    00510 pid_t KProcess::pid() const
    00511 {
    00512   return pid_;
    00513 }
    00514
    00515 #ifndef timersub
    00516 # define timersub(a, b, result) \
    00517   do { \
    00518     (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
    00519     (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
    00520     if ((result)->tv_usec < 0) { \
    00521       --(result)->tv_sec; \
    00522       (result)->tv_usec += 1000000; \
    00523     } \
    00524   } while (0)
    00525 #endif
    00526
    00527 bool KProcess::wait(int timeout)
    00528 {
    00529   if (!runs)
    00530     return true;
    00531
    00532 #ifndef __linux__
    00533   struct timeval etv;
    00534 #endif
    00535   struct timeval tv, *tvp;
    00536   if (timeout < 0)
    00537     tvp = 0;
    00538   else
    00539   {
    00540 #ifndef __linux__
    00541     gettimeofday(&etv, 0);
    00542     etv.tv_sec += timeout;
    00543 #else
    00544     tv.tv_sec = timeout;
    00545     tv.tv_usec = 0;
    00546 #endif
    00547     tvp = &tv;
    00548   }
    00549
    00550 #ifdef Q_OS_UNIX
    00551   int fd = KProcessController::theKProcessController->notifierFd();
    00552   for(;;)
    00553   {
    00554     fd_set fds;
    00555     FD_ZERO( &fds );
    00556     FD_SET( fd, &fds );
    00557
    00558 #ifndef __linux__
    00559     if (tvp)
    00560     {
    00561       gettimeofday(&tv, 0);
    00562       timersub(&etv, &tv, &tv);
    00563       if (tv.tv_sec < 0)
    00564         tv.tv_sec = tv.tv_usec = 0;
    00565     }
    00566 #endif
    00567
    00568     switch( select( fd+1, &fds, 0, 0, tvp ) )
    00569     {
    00570     case -1:
    00571       if( errno == EINTR )
    00572         break;
    00573       // fall through; should happen if tvp->tv_sec < 0
    00574     case 0:
    00575       KProcessController::theKProcessController->rescheduleCheck();
    00576       return false;
    00577     default:
    00578       KProcessController::theKProcessController->unscheduleCheck();
    00579       if (waitpid(pid_, &status, WNOHANG) != 0) // error finishes, too
    00580       {
    00581         processHasExited(status);
    00582         KProcessController::theKProcessController->rescheduleCheck();
    00583         return true;
    00584       }
    00585     }
    00586   }
    00587 #endif //Q_OS_UNIX
    00588   return false;
    00589 }
    00590
    00591
    00592
    00593 bool KProcess::normalExit() const
    00594 {
    00595   return (pid_ != 0) && !runs && WIFEXITED(status);
    00596 }
    00597
    00598
    00599 bool KProcess::signalled() const
    00600 {
    00601   return (pid_ != 0) && !runs && WIFSIGNALED(status);
    00602 }
    00603
    00604
    00605 bool KProcess::coreDumped() const
    00606 {
    00607 #ifdef WCOREDUMP
    00608   return signalled() && WCOREDUMP(status);
    00609 #else
    00610   return false;
    00611 #endif
    00612 }
    00613
    00614
    00615 int KProcess::exitStatus() const
    00616 {
    00617   return WEXITSTATUS(status);
    00618 }
    00619
    00620
    00621 int KProcess::exitSignal() const
    00622 {
    00623   return WTERMSIG(status);
    00624 }
    00625
    00626
    00627 bool KProcess::writeStdin(const char *buffer, int buflen)
    00628 {
    00629   // if there is still data pending, writing new data
    00630   // to stdout is not allowed (since it could also confuse
    00631   // kprocess ...)
    00632   if (input_data != 0)
    00633     return false;
    00634
    00635   if (communication & Stdin) {
    00636     input_data = buffer;
    00637     input_sent = 0;
    00638     input_total = buflen;
    00639     innot->setEnabled(true);
    00640     if (input_total)
    00641        slotSendData(0);
    00642     return true;
    00643   } else
    00644     return false;
    00645 }
    00646
    00647 void KProcess::suspend()
    00648 {
    00649   if (outnot)
    00650      outnot->setEnabled(false);
    00651 }
    00652
    00653 void KProcess::resume()
    00654 {
    00655   if (outnot)
    00656      outnot->setEnabled(true);
    00657 }
    00658
    00659 bool KProcess::closeStdin()
    00660 {
    00661   if (communication & Stdin) {
    00662     communication = (Communication) (communication & ~Stdin);
    00663     delete innot;
    00664     innot = 0;
    00665     if (!(d->usePty & Stdin))
    00666       close(in[1]);
    00667     in[1] = -1;
    00668     return true;
    00669   } else
    00670     return false;
    00671 }
    00672
    00673 bool KProcess::closeStdout()
    00674 {
    00675   if (communication & Stdout) {
    00676     communication = (Communication) (communication & ~Stdout);
    00677     delete outnot;
    00678     outnot = 0;
    00679     if (!(d->usePty & Stdout))
    00680       close(out[0]);
    00681     out[0] = -1;
    00682     return true;
    00683   } else
    00684     return false;
    00685 }
    00686
    00687 bool KProcess::closeStderr()
    00688 {
    00689   if (communication & Stderr) {
    00690     communication = (Communication) (communication & ~Stderr);
    00691     delete errnot;
    00692     errnot = 0;
    00693     if (!(d->usePty & Stderr))
    00694       close(err[0]);
    00695     err[0] = -1;
    00696     return true;
    00697   } else
    00698     return false;
    00699 }
    00700
    00701 bool KProcess::closePty()
    00702 {
    00703 #ifdef Q_OS_UNIX
    00704   if (d->pty && d->pty->masterFd() >= 0) {
    00705     if (d->addUtmp)
    00706       d->pty->logout();
    00707     d->pty->close();
    00708     return true;
    00709   } else
    00710     return false;
    00711 #else
    00712     return false;
    00713 #endif
    00714 }
    00715
    00716 void KProcess::closeAll()
    00717 {
    00718   closeStdin();
    00719   closeStdout();
    00720   closeStderr();
    00721   closePty();
    00722 }
    00723
    00725 // protected slots         //
    00727
    00728
    00729
    00730 void KProcess::slotChildOutput(int fdno)
    00731 {
    00732   if (!childOutput(fdno))
    00733      closeStdout();
    00734 }
    00735
    00736
    00737 void KProcess::slotChildError(int fdno)
    00738 {
    00739   if (!childError(fdno))
    00740      closeStderr();
    00741 }
    00742
    00743
    00744 void KProcess::slotSendData(int)
    00745 {
    00746   if (input_sent == input_total) {
    00747     innot->setEnabled(false);
    00748     input_data = 0;
    00749     emit wroteStdin(this);
    00750   } else {
    00751     int result = ::write(in[1], input_data+input_sent, input_total-input_sent);
    00752     if (result >= 0)
    00753     {
    00754        input_sent += result;
    00755     }
    00756     else if ((errno != EAGAIN) && (errno != EINTR))
    00757     {
    00758        kdDebug(175) << "Error writing to stdin of child process" << endl;
    00759        closeStdin();
    00760     }
    00761   }
    00762 }
    00763
    00764 void KProcess::setUseShell(bool useShell, const char *shell)
    00765 {
    00766   d->useShell = useShell;
    00767   if (shell && *shell)
    00768     d->shell = shell;
    00769   else
    00770 // #ifdef NON_FREE // ... as they ship non-POSIX /bin/sh
    00771 #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__GNU__)
    00772   // Solaris POSIX ...
    00773   if (!access( "/usr/xpg4/bin/sh", X_OK ))
    00774     d->shell = "/usr/xpg4/bin/sh";
    00775   else
    00776   // ... which links here anyway
    00777   if (!access( "/bin/ksh", X_OK ))
    00778     d->shell = "/bin/ksh";
    00779   else
    00780   // dunno, maybe superfluous?
    00781   if (!access( "/usr/ucb/sh", X_OK ))
    00782     d->shell = "/usr/ucb/sh";
    00783   else
    00784 #endif
    00785     d->shell = "/bin/sh";
    00786 }
    00787
    00788 #ifdef Q_OS_UNIX
    00789 void KProcess::setUsePty(Communication usePty, bool addUtmp)
    00790 {
    00791   d->usePty = usePty;
    00792   d->addUtmp = addUtmp;
    00793   if (usePty) {
    00794     if (!d->pty)
    00795       d->pty = new KPty;
    00796   } else {
    00797     delete d->pty;
    00798     d->pty = 0;
    00799   }
    00800 }
    00801
    00802 KPty *KProcess::pty() const
    00803 {
    00804   return d->pty;
    00805 }
    00806 #endif //Q_OS_UNIX
    00807
    00808 QString KProcess::quote(const QString &arg)
    00809 {
    00810     QChar q('\'');
    00811     return QString(arg).replace(q, "'\\''").prepend(q).append(q);
    00812 }
    00813
    00814
    00816 // private member functions //
    00818
    00819
    00820 void KProcess::processHasExited(int state)
    00821 {
    00822     // only successfully run NotifyOnExit processes ever get here
    00823
    00824     status = state;
    00825     runs = false; // do this before commClose, so it knows we're dead
    00826
    00827     commClose(); // cleanup communication sockets
    00828
    00829     if (run_mode != DontCare)
    00830       emit processExited(this);
    00831 }
    00832
    00833
    00834
    00835 int KProcess::childOutput(int fdno)
    00836 {
    00837   if (communication & NoRead) {
    00838      int len = -1;
    00839      emit receivedStdout(fdno, len);
    00840      errno = 0; // Make sure errno doesn't read "EAGAIN"
    00841      return len;
    00842   }
    00843   else
    00844   {
    00845      char buffer[1025];
    00846      int len;
    00847
    00848      len = ::read(fdno, buffer, 1024);
    00849
    00850      if (len > 0) {
    00851         buffer[len] = 0; // Just in case.
    00852         emit receivedStdout(this, buffer, len);
    00853      }
    00854      return len;
    00855   }
    00856 }
    00857
    00858 int KProcess::childError(int fdno)
    00859 {
    00860   char buffer[1025];
    00861   int len;
    00862
    00863   len = ::read(fdno, buffer, 1024);
    00864
    00865   if (len > 0) {
    00866      buffer[len] = 0; // Just in case.
    00867      emit receivedStderr(this, buffer, len);
    00868   }
    00869   return len;
    00870 }
    00871
    00872
    00873 int KProcess::setupCommunication(Communication comm)
    00874 {
    00875 #ifdef Q_OS_UNIX
    00876   // PTY stuff //
    00877   if (d->usePty)
    00878   {
    00879     // cannot communicate on both stderr and stdout if they are both on the pty
    00880     if (!(~(comm & d->usePty) & (Stdout | Stderr))) {
    00881        kdWarning(175) << "Invalid usePty/communication combination (" << d->usePty << "/" << comm << ")" << endl;
    00882        return 0;
    00883     }
    00884     if (!d->pty->open())
    00885        return 0;
    00886
    00887     int rcomm = comm & d->usePty;
    00888     int mfd = d->pty->masterFd();
    00889     if (rcomm & Stdin)
    00890       in[1] = mfd;
    00891     if (rcomm & Stdout)
    00892       out[0] = mfd;
    00893     if (rcomm & Stderr)
    00894       err[0] = mfd;
    00895   }
    00896
    00897   communication = comm;
    00898
    00899   comm = (Communication) (comm & ~d->usePty);
    00900   if (comm & Stdin) {
    00901     if (socketpair(AF_UNIX, SOCK_STREAM, 0, in))
    00902       goto fail0;
    00903     fcntl(in[0], F_SETFD, FD_CLOEXEC);
    00904     fcntl(in[1], F_SETFD, FD_CLOEXEC);
    00905   }
    00906   if (comm & Stdout) {
    00907     if (socketpair(AF_UNIX, SOCK_STREAM, 0, out))
    00908       goto fail1;
    00909     fcntl(out[0], F_SETFD, FD_CLOEXEC);
    00910     fcntl(out[1], F_SETFD, FD_CLOEXEC);
    00911   }
    00912   if (comm & Stderr) {
    00913     if (socketpair(AF_UNIX, SOCK_STREAM, 0, err))
    00914       goto fail2;
    00915     fcntl(err[0], F_SETFD, FD_CLOEXEC);
    00916     fcntl(err[1], F_SETFD, FD_CLOEXEC);
    00917   }
    00918   return 1; // Ok
    00919  fail2:
    00920   if (comm & Stdout)
    00921   {
    00922     close(out[0]);
    00923     close(out[1]);
    00924     out[0] = out[1] = -1;
    00925   }
    00926  fail1:
    00927   if (comm & Stdin)
    00928   {
    00929     close(in[0]);
    00930     close(in[1]);
    00931     in[0] = in[1] = -1;
    00932   }
    00933  fail0:
    00934   communication = NoCommunication;
    00935 #endif //Q_OS_UNIX
    00936   return 0; // Error
    00937 }
    00938
    00939
    00940
    00941 int KProcess::commSetupDoneP()
    00942 {
    00943   int rcomm = communication & ~d->usePty;
    00944   if (rcomm & Stdin)
    00945     close(in[0]);
    00946   if (rcomm & Stdout)
    00947     close(out[1]);
    00948   if (rcomm & Stderr)
    00949     close(err[1]);
    00950   in[0] = out[1] = err[1] = -1;
    00951
    00952   // Don't create socket notifiers if no interactive comm is to be expected
    00953   if (run_mode != NotifyOnExit && run_mode != OwnGroup)
    00954     return 1;
    00955
    00956   if (communication & Stdin) {
    00957     fcntl(in[1], F_SETFL, O_NONBLOCK | fcntl(in[1], F_GETFL));
    00958     innot =  new QSocketNotifier(in[1], QSocketNotifier::Write, this);
    00959     Q_CHECK_PTR(innot);
    00960     innot->setEnabled(false); // will be enabled when data has to be sent
    00961     QObject::connect(innot, SIGNAL(activated(int)),
    00962                      this, SLOT(slotSendData(int)));
    00963   }
    00964
    00965   if (communication & Stdout) {
    00966     outnot = new QSocketNotifier(out[0], QSocketNotifier::Read, this);
    00967     Q_CHECK_PTR(outnot);
    00968     QObject::connect(outnot, SIGNAL(activated(int)),
    00969                      this, SLOT(slotChildOutput(int)));
    00970     if (communication & NoRead)
    00971         suspend();
    00972   }
    00973
    00974   if (communication & Stderr) {
    00975     errnot = new QSocketNotifier(err[0], QSocketNotifier::Read, this );
    00976     Q_CHECK_PTR(errnot);
    00977     QObject::connect(errnot, SIGNAL(activated(int)),
    00978                      this, SLOT(slotChildError(int)));
    00979   }
    00980
    00981   return 1;
    00982 }
    00983
    00984
    00985
    00986 int KProcess::commSetupDoneC()
    00987 {
    00988   int ok = 1;
    00989 #ifdef Q_OS_UNIX
    00990
    00991   if (d->usePty & Stdin) {
    00992     if (dup2(d->pty->slaveFd(), STDIN_FILENO) < 0) ok = 0;
    00993   } else if (communication & Stdin) {
    00994     if (dup2(in[0], STDIN_FILENO) < 0) ok = 0;
    00995   } else {
    00996     int null_fd = open( "/dev/null", O_RDONLY );
    00997     if (dup2( null_fd, STDIN_FILENO ) < 0) ok = 0;
    00998     close( null_fd );
    00999   }
    01000   struct linger so;
    01001   memset(&so, 0, sizeof(so));
    01002   if (d->usePty & Stdout) {
    01003     if (dup2(d->pty->slaveFd(), STDOUT_FILENO) < 0) ok = 0;
    01004   } else if (communication & Stdout) {
    01005     if (dup2(out[1], STDOUT_FILENO) < 0 ||
    01006         setsockopt(out[1], SOL_SOCKET, SO_LINGER, (char *)&so, sizeof(so)))
    01007       ok = 0;
    01008   }
    01009   if (d->usePty & Stderr) {
    01010     if (dup2(d->pty->slaveFd(), STDERR_FILENO) < 0) ok = 0;
    01011   } else if (communication & Stderr) {
    01012     if (dup2(err[1], STDERR_FILENO) < 0 ||
    01013         setsockopt(err[1], SOL_SOCKET, SO_LINGER, (char *)&so, sizeof(so)))
    01014       ok = 0;
    01015   }
    01016
    01017   // don't even think about closing all open fds here or anywhere else
    01018
    01019   // PTY stuff //
    01020   if (d->usePty) {
    01021     d->pty->setCTty();
    01022     if (d->addUtmp)
    01023       d->pty->login(KUser(KUser::UseRealUserID).loginName().local8Bit().data(), getenv("DISPLAY"));
    01024   }
    01025 #endif //Q_OS_UNIX
    01026
    01027   return ok;
    01028 }
    01029
    01030
    01031
    01032 void KProcess::commClose()
    01033 {
    01034   closeStdin();
    01035
    01036 #ifdef Q_OS_UNIX
    01037   if (pid_) { // detached, failed, and killed processes have no output. basta. :)
    01038     // If both channels are being read we need to make sure that one socket
    01039     // buffer doesn't fill up whilst we are waiting for data on the other
    01040     // (causing a deadlock). Hence we need to use select.
    01041
    01042     int notfd = KProcessController::theKProcessController->notifierFd();
    01043
    01044     while ((communication & (Stdout | Stderr)) || runs) {
    01045       fd_set rfds;
    01046       FD_ZERO(&rfds);
    01047       struct timeval timeout, *p_timeout;
    01048
    01049       int max_fd = 0;
    01050       if (communication & Stdout) {
    01051         FD_SET(out[0], &rfds);
    01052         max_fd = out[0];
    01053       }
    01054       if (communication & Stderr) {
    01055         FD_SET(err[0], &rfds);
    01056         if (err[0] > max_fd)
    01057           max_fd = err[0];
    01058       }
    01059       if (runs) {
    01060         FD_SET(notfd, &rfds);
    01061         if (notfd > max_fd)
    01062           max_fd = notfd;
    01063         // If the process is still running we block until we
    01064         // receive data or the process exits.
    01065         p_timeout = 0; // no timeout
    01066       } else {
    01067         // If the process has already exited, we only check
    01068         // the available data, we don't wait for more.
    01069         timeout.tv_sec = timeout.tv_usec = 0; // timeout immediately
    01070         p_timeout = &timeout;
    01071       }
    01072
    01073       int fds_ready = select(max_fd+1, &rfds, 0, 0, p_timeout);
    01074       if (fds_ready < 0) {
    01075         if (errno == EINTR)
    01076           continue;
    01077         break;
    01078       } else if (!fds_ready)
    01079         break;
    01080
    01081       if ((communication & Stdout) && FD_ISSET(out[0], &rfds))
    01082         slotChildOutput(out[0]);
    01083
    01084       if ((communication & Stderr) && FD_ISSET(err[0], &rfds))
    01085         slotChildError(err[0]);
    01086
    01087       if (runs && FD_ISSET(notfd, &rfds)) {
    01088         runs = false; // hack: signal potential exit
    01089         return; // don't close anything, we will be called again
    01090       }
    01091     }
    01092   }
    01093 #endif //Q_OS_UNIX
    01094
    01095   closeStdout();
    01096   closeStderr();
    01097
    01098   closePty();
    01099 }
    01100
    01101
    01102 void KProcess::virtual_hook( int, void* )
    01103 { /*BASE::virtual_hook( id, data );*/ }
    01104
    01105
    01107 // CC: Class KShellProcess
    01109
    01110 KShellProcess::KShellProcess(const char *shellname):
    01111   KProcess()
    01112 {
    01113   setUseShell( true, shellname ? shellname : getenv("SHELL") );
    01114 }
    01115
    01116 KShellProcess::~KShellProcess() {
    01117 }
    01118
    01119 QString KShellProcess::quote(const QString &arg)
    01120 {
    01121     return KProcess::quote(arg);
    01122 }
    01123
    01124 bool KShellProcess::start(RunMode runmode, Communication comm)
    01125 {
    01126   return KProcess::start(runmode, comm);
    01127 }
    01128
    01129 void KShellProcess::virtual_hook( int id, void* data )
    01130 { KProcess::virtual_hook( id, data ); }
    01131
    01132 #include "kprocess.moc"

This file is part of the documentation for kdecore Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:18:09 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003