• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KDECore

kprocess.cpp

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

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal