kprocess.cpp

00001 /*
00002 
00003    $Id: kprocess.cpp 524676 2006-03-30 22:04:03Z hasso $
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., 51 Franklin Street, Fifth Floor,
00021    Boston, MA 02110-1301, 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   // we don't use vfork() because
00359   // - it has unclear semantics and is not standardized
00360   // - we do way too much magic in the child
00361   pid_ = fork();
00362   if (pid_ == 0) {
00363         // The child process
00364 
00365         close(fd[0]);
00366         // Closing of fd[1] indicates that the execvp() succeeded!
00367         fcntl(fd[1], F_SETFD, FD_CLOEXEC);
00368 
00369         if (!commSetupDoneC())
00370           kdDebug(175) << "Could not finish comm setup in child!" << endl;
00371 
00372         // reset all signal handlers
00373         struct sigaction act;
00374         sigemptyset(&act.sa_mask);
00375         act.sa_handler = SIG_DFL;
00376         act.sa_flags = 0;
00377         for (int sig = 1; sig < NSIG; sig++)
00378           sigaction(sig, &act, 0L);
00379 
00380         if (d->priority)
00381             setpriority(PRIO_PROCESS, 0, d->priority);
00382 
00383         if (!runPrivileged())
00384         {
00385            setgid(getgid());
00386 #ifdef HAVE_INITGROUPS
00387            if (pw)
00388               initgroups(pw->pw_name, pw->pw_gid);
00389 #endif
00390            setuid(getuid());
00391         }
00392 
00393         setupEnvironment();
00394 
00395         if (runmode == DontCare || runmode == OwnGroup)
00396           setsid();
00397 
00398         const char *executable = arglist[0];
00399         if (!d->executable.isEmpty())
00400            executable = d->executable.data();
00401         execvp(executable, arglist);
00402 
00403         char resultByte = 1;
00404         write(fd[1], &resultByte, 1);
00405         _exit(-1);
00406   } else if (pid_ == -1) {
00407         // forking failed
00408 
00409         // commAbort();
00410         pid_ = 0;
00411         free(arglist);
00412         return false;
00413   }
00414   // the parent continues here
00415   free(arglist);
00416 
00417   if (!commSetupDoneP())
00418     kdDebug(175) << "Could not finish comm setup in parent!" << endl;
00419 
00420   // Check whether client could be started.
00421   close(fd[1]);
00422   for(;;)
00423   {
00424      char resultByte;
00425      int n = ::read(fd[0], &resultByte, 1);
00426      if (n == 1)
00427      {
00428          // exec() failed
00429          close(fd[0]);
00430          waitpid(pid_, 0, 0);
00431          pid_ = 0;
00432          commClose();
00433          return false;
00434      }
00435      if (n == -1)
00436      {
00437         if (errno == EINTR)
00438            continue; // Ignore
00439      }
00440      break; // success
00441   }
00442   close(fd[0]);
00443 
00444   runs = true;
00445   switch (runmode)
00446   {
00447   case Block:
00448     for (;;)
00449     {
00450       commClose(); // drain only, unless obsolete reimplementation
00451       if (!runs)
00452       {
00453         // commClose detected data on the process exit notifification pipe
00454         KProcessController::theKProcessController->unscheduleCheck();
00455         if (waitpid(pid_, &status, WNOHANG) != 0) // error finishes, too
00456         {
00457           commClose(); // this time for real (runs is false)
00458           KProcessController::theKProcessController->rescheduleCheck();
00459           break;
00460         }
00461         runs = true; // for next commClose() iteration
00462       }
00463       else
00464       {
00465         // commClose is an obsolete reimplementation and waited until
00466         // all output channels were closed (or it was interrupted).
00467         // there is a chance that it never gets here ...
00468         waitpid(pid_, &status, 0);
00469         runs = false;
00470         break;
00471       }
00472     }
00473     // why do we do this? i think this signal should be emitted _only_
00474     // after the process has successfully run _asynchronously_ --ossi
00475     emit processExited(this);
00476     break;
00477   default: // NotifyOnExit & OwnGroup
00478     input_data = 0; // Discard any data for stdin that might still be there
00479     break;
00480   }
00481   return true;
00482 #else
00483   //TODO
00484   return false;
00485 #endif
00486 }
00487 
00488 
00489 
00490 bool KProcess::kill(int signo)
00491 {
00492 #ifdef Q_OS_UNIX
00493   if (runs && pid_ > 0 && !::kill(run_mode == OwnGroup ? -pid_ : pid_, signo))
00494     return true;
00495 #endif
00496   return false;
00497 }
00498 
00499 
00500 
00501 bool KProcess::isRunning() const
00502 {
00503   return runs;
00504 }
00505 
00506 
00507 
00508 pid_t KProcess::pid() const
00509 {
00510   return pid_;
00511 }
00512 
00513 #ifndef timersub
00514 # define timersub(a, b, result) \
00515   do { \
00516     (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
00517     (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
00518     if ((result)->tv_usec < 0) { \
00519       --(result)->tv_sec; \
00520       (result)->tv_usec += 1000000; \
00521     } \
00522   } while (0)
00523 #endif
00524 
00525 bool KProcess::wait(int timeout)
00526 {
00527   if (!runs)
00528     return true;
00529 
00530 #ifndef __linux__
00531   struct timeval etv;
00532 #endif
00533   struct timeval tv, *tvp;
00534   if (timeout < 0)
00535     tvp = 0;
00536   else
00537   {
00538 #ifndef __linux__
00539     gettimeofday(&etv, 0);
00540     etv.tv_sec += timeout;
00541 #else
00542     tv.tv_sec = timeout;
00543     tv.tv_usec = 0;
00544 #endif
00545     tvp = &tv;
00546   }
00547 
00548 #ifdef Q_OS_UNIX
00549   int fd = KProcessController::theKProcessController->notifierFd();
00550   for(;;)
00551   {
00552     fd_set fds;
00553     FD_ZERO( &fds );
00554     FD_SET( fd, &fds );
00555 
00556 #ifndef __linux__
00557     if (tvp)
00558     {
00559       gettimeofday(&tv, 0);
00560       timersub(&etv, &tv, &tv);
00561       if (tv.tv_sec < 0)
00562         tv.tv_sec = tv.tv_usec = 0;
00563     }
00564 #endif
00565 
00566     switch( select( fd+1, &fds, 0, 0, tvp ) )
00567     {
00568     case -1:
00569       if( errno == EINTR )
00570         break;
00571       // fall through; should happen if tvp->tv_sec < 0
00572     case 0:
00573       KProcessController::theKProcessController->rescheduleCheck();
00574       return false;
00575     default:
00576       KProcessController::theKProcessController->unscheduleCheck();
00577       if (waitpid(pid_, &status, WNOHANG) != 0) // error finishes, too
00578       {
00579         processHasExited(status);
00580         KProcessController::theKProcessController->rescheduleCheck();
00581         return true;
00582       }
00583     }
00584   }
00585 #endif //Q_OS_UNIX
00586   return false;
00587 }
00588 
00589 
00590 
00591 bool KProcess::normalExit() const
00592 {
00593   return (pid_ != 0) && !runs && WIFEXITED(status);
00594 }
00595 
00596 
00597 bool KProcess::signalled() const
00598 {
00599   return (pid_ != 0) && !runs && WIFSIGNALED(status);
00600 }
00601 
00602 
00603 bool KProcess::coreDumped() const
00604 {
00605 #ifdef WCOREDUMP
00606   return signalled() && WCOREDUMP(status);
00607 #else
00608   return false;
00609 #endif
00610 }
00611 
00612 
00613 int KProcess::exitStatus() const
00614 {
00615   return WEXITSTATUS(status);
00616 }
00617 
00618 
00619 int KProcess::exitSignal() const
00620 {
00621   return WTERMSIG(status);
00622 }
00623 
00624 
00625 bool KProcess::writeStdin(const char *buffer, int buflen)
00626 {
00627   // if there is still data pending, writing new data
00628   // to stdout is not allowed (since it could also confuse
00629   // kprocess ...)
00630   if (input_data != 0)
00631     return false;
00632 
00633   if (communication & Stdin) {
00634     input_data = buffer;
00635     input_sent = 0;
00636     input_total = buflen;
00637     innot->setEnabled(true);
00638     if (input_total)
00639        slotSendData(0);
00640     return true;
00641   } else
00642     return false;
00643 }
00644 
00645 void KProcess::suspend()
00646 {
00647   if (outnot)
00648      outnot->setEnabled(false);
00649 }
00650 
00651 void KProcess::resume()
00652 {
00653   if (outnot)
00654      outnot->setEnabled(true);
00655 }
00656 
00657 bool KProcess::closeStdin()
00658 {
00659   if (communication & Stdin) {
00660     communication = (Communication) (communication & ~Stdin);
00661     delete innot;
00662     innot = 0;
00663     if (!(d->usePty & Stdin))
00664       close(in[1]);
00665     in[1] = -1;
00666     return true;
00667   } else
00668     return false;
00669 }
00670 
00671 bool KProcess::closeStdout()
00672 {
00673   if (communication & Stdout) {
00674     communication = (Communication) (communication & ~Stdout);
00675     delete outnot;
00676     outnot = 0;
00677     if (!(d->usePty & Stdout))
00678       close(out[0]);
00679     out[0] = -1;
00680     return true;
00681   } else
00682     return false;
00683 }
00684 
00685 bool KProcess::closeStderr()
00686 {
00687   if (communication & Stderr) {
00688     communication = (Communication) (communication & ~Stderr);
00689     delete errnot;
00690     errnot = 0;
00691     if (!(d->usePty & Stderr))
00692       close(err[0]);
00693     err[0] = -1;
00694     return true;
00695   } else
00696     return false;
00697 }
00698 
00699 bool KProcess::closePty()
00700 {
00701 #ifdef Q_OS_UNIX
00702   if (d->pty && d->pty->masterFd() >= 0) {
00703     if (d->addUtmp)
00704       d->pty->logout();
00705     d->pty->close();
00706     return true;
00707   } else
00708     return false;
00709 #else
00710     return false;
00711 #endif
00712 }
00713 
00714 void KProcess::closeAll()
00715 {
00716   closeStdin();
00717   closeStdout();
00718   closeStderr();
00719   closePty();
00720 }
00721 
00723 // protected slots         //
00725 
00726 
00727 
00728 void KProcess::slotChildOutput(int fdno)
00729 {
00730   if (!childOutput(fdno))
00731      closeStdout();
00732 }
00733 
00734 
00735 void KProcess::slotChildError(int fdno)
00736 {
00737   if (!childError(fdno))
00738      closeStderr();
00739 }
00740 
00741 
00742 void KProcess::slotSendData(int)
00743 {
00744   if (input_sent == input_total) {
00745     innot->setEnabled(false);
00746     input_data = 0;
00747     emit wroteStdin(this);
00748   } else {
00749     int result = ::write(in[1], input_data+input_sent, input_total-input_sent);
00750     if (result >= 0)
00751     {
00752        input_sent += result;
00753     }
00754     else if ((errno != EAGAIN) && (errno != EINTR))
00755     {
00756        kdDebug(175) << "Error writing to stdin of child process" << endl;
00757        closeStdin();
00758     }
00759   }
00760 }
00761 
00762 void KProcess::setUseShell(bool useShell, const char *shell)
00763 {
00764   d->useShell = useShell;
00765   if (shell && *shell)
00766     d->shell = shell;
00767   else
00768 // #ifdef NON_FREE // ... as they ship non-POSIX /bin/sh
00769 #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__GNU__) && !defined(__DragonFly__)
00770   // Solaris POSIX ...
00771   if (!access( "/usr/xpg4/bin/sh", X_OK ))
00772     d->shell = "/usr/xpg4/bin/sh";
00773   else
00774   // ... which links here anyway
00775   if (!access( "/bin/ksh", X_OK ))
00776     d->shell = "/bin/ksh";
00777   else
00778   // dunno, maybe superfluous?
00779   if (!access( "/usr/ucb/sh", X_OK ))
00780     d->shell = "/usr/ucb/sh";
00781   else
00782 #endif
00783     d->shell = "/bin/sh";
00784 }
00785 
00786 #ifdef Q_OS_UNIX
00787 void KProcess::setUsePty(Communication usePty, bool addUtmp)
00788 {
00789   d->usePty = usePty;
00790   d->addUtmp = addUtmp;
00791   if (usePty) {
00792     if (!d->pty)
00793       d->pty = new KPty;
00794   } else {
00795     delete d->pty;
00796     d->pty = 0;
00797   }
00798 }
00799 
00800 KPty *KProcess::pty() const
00801 {
00802   return d->pty;
00803 }
00804 #endif //Q_OS_UNIX
00805 
00806 QString KProcess::quote(const QString &arg)
00807 {
00808     QChar q('\'');
00809     return QString(arg).replace(q, "'\\''").prepend(q).append(q);
00810 }
00811 
00812 
00814 // private member functions //
00816 
00817 
00818 void KProcess::processHasExited(int state)
00819 {
00820     // only successfully run NotifyOnExit processes ever get here
00821 
00822     status = state;
00823     runs = false; // do this before commClose, so it knows we're dead
00824 
00825     commClose(); // cleanup communication sockets
00826 
00827     if (run_mode != DontCare)
00828       emit processExited(this);
00829 }
00830 
00831 
00832 
00833 int KProcess::childOutput(int fdno)
00834 {
00835   if (communication & NoRead) {
00836      int len = -1;
00837      emit receivedStdout(fdno, len);
00838      errno = 0; // Make sure errno doesn't read "EAGAIN"
00839      return len;
00840   }
00841   else
00842   {
00843      char buffer[1025];
00844      int len;
00845 
00846      len = ::read(fdno, buffer, 1024);
00847      
00848      if (len > 0) {
00849         buffer[len] = 0; // Just in case.
00850         emit receivedStdout(this, buffer, len);
00851      }
00852      return len;
00853   }
00854 }
00855 
00856 int KProcess::childError(int fdno)
00857 {
00858   char buffer[1025];
00859   int len;
00860 
00861   len = ::read(fdno, buffer, 1024);
00862 
00863   if (len > 0) {
00864      buffer[len] = 0; // Just in case.
00865      emit receivedStderr(this, buffer, len);
00866   }
00867   return len;
00868 }
00869 
00870 
00871 int KProcess::setupCommunication(Communication comm)
00872 {
00873 #ifdef Q_OS_UNIX
00874   // PTY stuff //
00875   if (d->usePty)
00876   {
00877     // cannot communicate on both stderr and stdout if they are both on the pty
00878     if (!(~(comm & d->usePty) & (Stdout | Stderr))) {
00879        kdWarning(175) << "Invalid usePty/communication combination (" << d->usePty << "/" << comm << ")" << endl;
00880        return 0;
00881     }
00882     if (!d->pty->open())
00883        return 0;
00884 
00885     int rcomm = comm & d->usePty;
00886     int mfd = d->pty->masterFd();
00887     if (rcomm & Stdin)
00888       in[1] = mfd;
00889     if (rcomm & Stdout)
00890       out[0] = mfd;
00891     if (rcomm & Stderr)
00892       err[0] = mfd;
00893   }
00894 
00895   communication = comm;
00896 
00897   comm = (Communication) (comm & ~d->usePty);
00898   if (comm & Stdin) {
00899     if (socketpair(AF_UNIX, SOCK_STREAM, 0, in))
00900       goto fail0;
00901     fcntl(in[0], F_SETFD, FD_CLOEXEC);
00902     fcntl(in[1], F_SETFD, FD_CLOEXEC);
00903   }
00904   if (comm & Stdout) {
00905     if (socketpair(AF_UNIX, SOCK_STREAM, 0, out))
00906       goto fail1;
00907     fcntl(out[0], F_SETFD, FD_CLOEXEC);
00908     fcntl(out[1], F_SETFD, FD_CLOEXEC);
00909   }
00910   if (comm & Stderr) {
00911     if (socketpair(AF_UNIX, SOCK_STREAM, 0, err))
00912       goto fail2;
00913     fcntl(err[0], F_SETFD, FD_CLOEXEC);
00914     fcntl(err[1], F_SETFD, FD_CLOEXEC);
00915   }
00916   return 1; // Ok
00917  fail2:
00918   if (comm & Stdout)
00919   {
00920     close(out[0]);
00921     close(out[1]);
00922     out[0] = out[1] = -1;
00923   }
00924  fail1:
00925   if (comm & Stdin)
00926   {
00927     close(in[0]);
00928     close(in[1]);
00929     in[0] = in[1] = -1;
00930   }
00931  fail0:
00932   communication = NoCommunication;
00933 #endif //Q_OS_UNIX
00934   return 0; // Error
00935 }
00936 
00937 
00938 
00939 int KProcess::commSetupDoneP()
00940 {
00941   int rcomm = communication & ~d->usePty;
00942   if (rcomm & Stdin)
00943     close(in[0]);
00944   if (rcomm & Stdout)
00945     close(out[1]);
00946   if (rcomm & Stderr)
00947     close(err[1]);
00948   in[0] = out[1] = err[1] = -1;
00949 
00950   // Don't create socket notifiers if no interactive comm is to be expected
00951   if (run_mode != NotifyOnExit && run_mode != OwnGroup)
00952     return 1;
00953 
00954   if (communication & Stdin) {
00955     fcntl(in[1], F_SETFL, O_NONBLOCK | fcntl(in[1], F_GETFL));
00956     innot =  new QSocketNotifier(in[1], QSocketNotifier::Write, this);
00957     Q_CHECK_PTR(innot);
00958     innot->setEnabled(false); // will be enabled when data has to be sent
00959     QObject::connect(innot, SIGNAL(activated(int)),
00960                      this, SLOT(slotSendData(int)));
00961   }
00962 
00963   if (communication & Stdout) {
00964     outnot = new QSocketNotifier(out[0], QSocketNotifier::Read, this);
00965     Q_CHECK_PTR(outnot);
00966     QObject::connect(outnot, SIGNAL(activated(int)),
00967                      this, SLOT(slotChildOutput(int)));
00968     if (communication & NoRead)
00969         suspend();
00970   }
00971 
00972   if (communication & Stderr) {
00973     errnot = new QSocketNotifier(err[0], QSocketNotifier::Read, this );
00974     Q_CHECK_PTR(errnot);
00975     QObject::connect(errnot, SIGNAL(activated(int)),
00976                      this, SLOT(slotChildError(int)));
00977   }
00978 
00979   return 1;
00980 }
00981 
00982 
00983 
00984 int KProcess::commSetupDoneC()
00985 {
00986   int ok = 1;
00987 #ifdef Q_OS_UNIX
00988 
00989   if (d->usePty & Stdin) {
00990     if (dup2(d->pty->slaveFd(), STDIN_FILENO) < 0) ok = 0;
00991   } else if (communication & Stdin) {
00992     if (dup2(in[0], STDIN_FILENO) < 0) ok = 0;
00993   } else {
00994     int null_fd = open( "/dev/null", O_RDONLY );
00995     if (dup2( null_fd, STDIN_FILENO ) < 0) ok = 0;
00996     close( null_fd );
00997   }
00998   struct linger so;
00999   memset(&so, 0, sizeof(so));
01000   if (d->usePty & Stdout) {
01001     if (dup2(d->pty->slaveFd(), STDOUT_FILENO) < 0) ok = 0;
01002   } else if (communication & Stdout) {
01003     if (dup2(out[1], STDOUT_FILENO) < 0 ||
01004         setsockopt(out[1], SOL_SOCKET, SO_LINGER, (char *)&so, sizeof(so)))
01005       ok = 0;
01006     if (communication & MergedStderr) {
01007       if (dup2(out[1], STDERR_FILENO) < 0)
01008         ok = 0;
01009     }
01010   }
01011   if (d->usePty & Stderr) {
01012     if (dup2(d->pty->slaveFd(), STDERR_FILENO) < 0) ok = 0;
01013   } else if (communication & Stderr) {
01014     if (dup2(err[1], STDERR_FILENO) < 0 ||
01015         setsockopt(err[1], SOL_SOCKET, SO_LINGER, (char *)&so, sizeof(so)))
01016       ok = 0;
01017   }
01018 
01019   // don't even think about closing all open fds here or anywhere else
01020 
01021   // PTY stuff //
01022   if (d->usePty) {
01023     d->pty->setCTty();
01024     if (d->addUtmp)
01025       d->pty->login(KUser(KUser::UseRealUserID).loginName().local8Bit().data(), getenv("DISPLAY"));
01026   }
01027 #endif //Q_OS_UNIX
01028 
01029   return ok;
01030 }
01031 
01032 
01033 
01034 void KProcess::commClose()
01035 {
01036   closeStdin();
01037 
01038 #ifdef Q_OS_UNIX
01039   if (pid_) { // detached, failed, and killed processes have no output. basta. :)
01040     // If both channels are being read we need to make sure that one socket
01041     // buffer doesn't fill up whilst we are waiting for data on the other
01042     // (causing a deadlock). Hence we need to use select.
01043 
01044     int notfd = KProcessController::theKProcessController->notifierFd();
01045 
01046     while ((communication & (Stdout | Stderr)) || runs) {
01047       fd_set rfds;
01048       FD_ZERO(&rfds);
01049       struct timeval timeout, *p_timeout;
01050 
01051       int max_fd = 0;
01052       if (communication & Stdout) {
01053         FD_SET(out[0], &rfds);
01054         max_fd = out[0];
01055       }
01056       if (communication & Stderr) {
01057         FD_SET(err[0], &rfds);
01058         if (err[0] > max_fd)
01059           max_fd = err[0];
01060       }
01061       if (runs) {
01062         FD_SET(notfd, &rfds);
01063         if (notfd > max_fd)
01064           max_fd = notfd;
01065         // If the process is still running we block until we
01066         // receive data or the process exits.
01067         p_timeout = 0; // no timeout
01068       } else {
01069         // If the process has already exited, we only check
01070         // the available data, we don't wait for more.
01071         timeout.tv_sec = timeout.tv_usec = 0; // timeout immediately
01072         p_timeout = &timeout;
01073       }
01074 
01075       int fds_ready = select(max_fd+1, &rfds, 0, 0, p_timeout);
01076       if (fds_ready < 0) {
01077         if (errno == EINTR)
01078           continue;
01079         break;
01080       } else if (!fds_ready)
01081         break;
01082 
01083       if ((communication & Stdout) && FD_ISSET(out[0], &rfds))
01084         slotChildOutput(out[0]);
01085 
01086       if ((communication & Stderr) && FD_ISSET(err[0], &rfds))
01087         slotChildError(err[0]);
01088 
01089       if (runs && FD_ISSET(notfd, &rfds)) {
01090         runs = false; // hack: signal potential exit
01091         return; // don't close anything, we will be called again
01092       }
01093     }
01094   }
01095 #endif //Q_OS_UNIX
01096 
01097   closeStdout();
01098   closeStderr();
01099 
01100   closePty();
01101 }
01102 
01103 
01104 void KProcess::virtual_hook( int, void* )
01105 { /*BASE::virtual_hook( id, data );*/ }
01106 
01107 
01109 // CC: Class KShellProcess
01111 
01112 KShellProcess::KShellProcess(const char *shellname):
01113   KProcess()
01114 {
01115   setUseShell( true, shellname ? shellname : getenv("SHELL") );
01116 }
01117 
01118 KShellProcess::~KShellProcess() {
01119 }
01120 
01121 QString KShellProcess::quote(const QString &arg)
01122 {
01123     return KProcess::quote(arg);
01124 }
01125 
01126 bool KShellProcess::start(RunMode runmode, Communication comm)
01127 {
01128   return KProcess::start(runmode, comm);
01129 }
01130 
01131 void KShellProcess::virtual_hook( int id, void* data )
01132 { KProcess::virtual_hook( id, data ); }
01133 
01134 #include "kprocess.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys