kdecore Library API Documentation

kprocess.cpp

00001 /*
00002 
00003    $Id: kprocess.cpp,v 1.133 2004/09/21 09:47:32 ossi Exp $
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"
KDE Logo
This file is part of the documentation for kdecore Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed May 4 06:54:19 2005 by doxygen 1.4.2 written by Dimitri van Heesch, © 1997-2003