kdecore Library API Documentation

kprocess.cpp

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