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

KDE3Support

k3process.cpp

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

KDE3Support

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
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