| # kdecore Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Source Files

# kprocess.cpp

    00001 /*
    00002
    00003    $Id: kprocess.cpp,v 1.88.2.3 2003/02/19 13:13:13 waba Exp $
    00004
    00005    This file is part of the KDE libraries
    00006    Copyright (C) 1997 Christian Czezatke (e9025461@student.tuwien.ac.at)
    00007
    00008    This library is free software; you can redistribute it and/or
    00009    modify it under the terms of the GNU Library General Public
    00010    License as published by the Free Software Foundation; either
    00011    version 2 of the License, or (at your option) any later version.
    00012
    00013    This library is distributed in the hope that it will be useful,
    00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
    00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    00016    Library General Public License for more details.
    00017
    00018    You should have received a copy of the GNU Library General Public License
    00019    along with this library; see the file COPYING.LIB.  If not, write to
    00020    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    00021    Boston, MA 02111-1307, USA.
    00022 */
    00023
    00024
    00025 //
    00026 //  KPROCESS -- A class for handling child processes in KDE without
    00027 //  having to take care of Un*x specific implementation details
    00028 //
    00029 //  version 0.3.1, Jan 8th 1998
    00030 //
    00031 //  (C) Christian Czezatke
    00032 //  e9025461@student.tuwien.ac.at
    00033 //
    00034 // Changes:
    00035 //
    00036 // March 2nd, 1998: Changed parameter list for KShellProcess:
    00037 //   Arguments are now placed in a single string so that
    00038 //   <shell> -c <commandstring> is passed to the shell
    00039 //   to make the use of "operator<<" consistent with KProcess
    00040
    00041 #include "kprocess.h"
    00042 #define _MAY_INCLUDE_KPROCESSCONTROLLER_
    00043 #include "kprocctrl.h"
    00044
    00045 #include <config.h>
    00046
    00047 #include <qfile.h>
    00048 #include <qsocketnotifier.h>
    00049 #include <qregexp.h>
    00050
    00051 #include <sys/time.h>
    00052 #include <sys/types.h>
    00053 #include <sys/stat.h>
    00054 #include <sys/socket.h>
    00055
    00056 #include <errno.h>
    00057 #include <fcntl.h>
    00058 #include <stdlib.h>
    00059 #include <signal.h>
    00060 #include <stdio.h>
    00061 #include <string.h>
    00062 #include <unistd.h>
    00063 #ifdef HAVE_SYS_SELECT_H
    00064 #include <sys/select.h>
    00065 #endif
    00066 #ifdef HAVE_INITGROUPS
    00067 #include <grp.h>
    00068 #endif
    00069 #include <pwd.h>
    00070
    00071 #include <qapplication.h>
    00072 #include <kdebug.h>
    00073
    00075 // public member functions //
    00077
    00078 class KProcessPrivate {
    00079 public:
    00080    KProcessPrivate() : useShell(false) { }
    00081
    00082    bool useShell;
    00083    QMap<QString,QString> env;
    00084    QString wd;
    00085    QCString shell;
    00086 };
    00087
    00088
    00089 KProcess::KProcess()
    00090   : QObject(),
    00091     run_mode(NotifyOnExit),
    00092     runs(false),
    00093     pid_(0),
    00094     status(0),
    00095     keepPrivs(false),
    00096     innot(0),
    00097     outnot(0),
    00098     errnot(0),
    00099     communication(NoCommunication),
    00100     input_data(0),
    00101     input_sent(0),
    00102     input_total(0),
    00103     d(0)
    00104 {
    00105   if (0 == KProcessController::theKProcessController) {
    00106         (void) new KProcessController();
    00107         Q_CHECK_PTR(KProcessController::theKProcessController);
    00108   }
    00109
    00110   KProcessController::theKProcessController->addKProcess(this);
    00111   out[0] = out[1] = -1;
    00112   in[0] = in[1] = -1;
    00113   err[0] = err[1] = -1;
    00114 }
    00115
    00116 void
    00117 KProcess::setEnvironment(const QString &name, const QString &value)
    00118 {
    00119    if (!d)
    00120       d = new KProcessPrivate;
    00121    d->env.insert(name, value);
    00122 }
    00123
    00124 void
    00125 KProcess::setWorkingDirectory(const QString &dir)
    00126 {
    00127    if (!d)
    00128       d = new KProcessPrivate;
    00129    d->wd = dir;
    00130 }
    00131
    00132 void
    00133 KProcess::setupEnvironment()
    00134 {
    00135    if (d)
    00136    {
    00137       QMap<QString,QString>::Iterator it;
    00138       for(it = d->env.begin(); it != d->env.end(); ++it)
    00139          setenv(QFile::encodeName(it.key()).data(),
    00140                 QFile::encodeName(it.data()).data(), 1);
    00141       if (!d->wd.isEmpty())
    00142          chdir(QFile::encodeName(d->wd).data());
    00143    }
    00144 }
    00145
    00146 void
    00147 KProcess::setRunPrivileged(bool keepPrivileges)
    00148 {
    00149    keepPrivs = keepPrivileges;
    00150 }
    00151
    00152 bool
    00153 KProcess::runPrivileged() const
    00154 {
    00155    return keepPrivs;
    00156 }
    00157
    00158
    00159 KProcess::~KProcess()
    00160 {
    00161   // destroying the KProcess instance sends a SIGKILL to the
    00162   // child process (if it is running) after removing it from the
    00163   // list of valid processes (if the process is not started as
    00164   // "DontCare")
    00165
    00166   KProcessController::theKProcessController->removeKProcess(this);
    00167   // this must happen before we kill the child
    00168   // TODO: block the signal while removing the current process from the process list
    00169
    00170   if (runs && (run_mode != DontCare))
    00171     kill(SIGKILL);
    00172
    00173   // Clean up open fd's and socket notifiers.
    00174   closeStdin();
    00175   closeStdout();
    00176   closeStderr();
    00177
    00178   // TODO: restore SIGCHLD and SIGPIPE handler if this is the last KProcess
    00179   delete d;
    00180 }
    00181
    00182 void KProcess::detach()
    00183 {
    00184   KProcessController::theKProcessController->removeKProcess(this);
    00185
    00186   runs = false;
    00187   pid_ = 0;
    00188
    00189   // Clean up open fd's and socket notifiers.
    00190   closeStdin();
    00191   closeStdout();
    00192   closeStderr();
    00193 }
    00194
    00195 bool KProcess::setExecutable(const QString& proc)
    00196 {
    00197   if (runs) return false;
    00198
    00199   if (proc.isEmpty())  return false;
    00200
    00201   if (!arguments.isEmpty())
    00202      arguments.remove(arguments.begin());
    00203   arguments.prepend(QFile::encodeName(proc));
    00204
    00205   return true;
    00206 }
    00207
    00208 KProcess &KProcess::operator<<(const QStringList& args)
    00209 {
    00210   QStringList::ConstIterator it = args.begin();
    00211   for ( ; it != args.end() ; ++it )
    00212       arguments.append(QFile::encodeName(*it));
    00213   return *this;
    00214 }
    00215
    00216 KProcess &KProcess::operator<<(const QCString& arg)
    00217 {
    00218   return operator<< (arg.data());
    00219 }
    00220
    00221 KProcess &KProcess::operator<<(const char* arg)
    00222 {
    00223   arguments.append(arg);
    00224   return *this;
    00225 }
    00226
    00227 KProcess &KProcess::operator<<(const QString& arg)
    00228 {
    00229   arguments.append(QFile::encodeName(arg));
    00230   return *this;
    00231 }
    00232
    00233 void KProcess::clearArguments()
    00234 {
    00235   arguments.clear();
    00236 }
    00237
    00238 bool KProcess::start(RunMode runmode, Communication comm)
    00239 {
    00240   uint i;
    00241   uint n = arguments.count();
    00242   char **arglist;
    00243
    00244   if (runs || (0 == n)) {
    00245         return false;  // cannot start a process that is already running
    00246         // or if no executable has been assigned
    00247   }
    00248   run_mode = runmode;
    00249   status = 0;
    00250
    00251   QCString shellCmd;
    00252   if (d && d->useShell)
    00253   {
    00254       if (d->shell.isEmpty())
    00255       {
    00256           kdDebug() << "Could not find a valid shell\n" << endl;
    00257               return false;
    00258       }
    00259
    00260       arglist = static_cast<char **>(malloc( (4)*sizeof(char *)));
    00261       for (i=0; i < n; i++) {
    00262           shellCmd += arguments[i];
    00263           shellCmd += " "; // CC: to separate the arguments
    00264       }
    00265
    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 (i=0; i < n; i++)
    00275          arglist[i] = arguments[i].data();
    00276       arglist[n]= 0;
    00277   }
    00278
    00279   if (!setupCommunication(comm))
    00280   {
    00281       kdDebug() << "Could not setup Communication!\n";
    00282       return false;
    00283   }
    00284
    00285   // We do this in the parent because if we do it in the child process
    00286   // gdb gets confused when the application runs from gdb.
    00287   uid_t uid = getuid();
    00288   gid_t gid = getgid();
    00289 #ifdef HAVE_INITGROUPS
    00290   struct passwd *pw = getpwuid(uid);
    00291 #endif
    00292
    00293   int fd[2];
    00294   if (0 > pipe(fd))
    00295   {
    00296      fd[0] = fd[1] = 0; // Pipe failed.. continue
    00297   }
    00298
    00299   runs = true;
    00300
    00301   QApplication::flushX();
    00302
    00303   // WABA: Note that we use fork() and not vfork() because
    00304   // vfork() has unclear semantics and is not standardized.
    00305   pid_ = fork();
    00306
    00307   if (0 == pid_) {
    00308         if (fd[0])
    00309            close(fd[0]);
    00310         if (!runPrivileged())
    00311         {
    00312            setgid(gid);
    00313 #if defined( HAVE_INITGROUPS)
    00314            if(pw)
    00315               initgroups(pw->pw_name, pw->pw_gid);
    00316 #endif
    00317            setuid(uid);
    00318         }
    00319         // The child process
    00320         if(!commSetupDoneC())
    00321           kdDebug() << "Could not finish comm setup in child!" << endl;
    00322
    00323         setupEnvironment();
    00324
    00325         // Matthias
    00326         if (run_mode == DontCare)
    00327           setpgid(0,0);
    00328         // restore default SIGPIPE handler (Harri)
    00329         struct sigaction act;
    00330         sigemptyset(&(act.sa_mask));
    00331         sigaddset(&(act.sa_mask), SIGPIPE);
    00332         act.sa_handler = SIG_DFL;
    00333         act.sa_flags = 0;
    00334         sigaction(SIGPIPE, &act, 0L);
    00335
    00336         // We set the close on exec flag.
    00337         // Closing of fd[1] indicates that the execvp succeeded!
    00338         if (fd[1])
    00339           fcntl(fd[1], F_SETFD, FD_CLOEXEC);
    00340         execvp(arglist[0], arglist);
    00341         char resultByte = 1;
    00342         if (fd[1])
    00343           write(fd[1], &resultByte, 1);
    00344         _exit(-1);
    00345   } else if (-1 == pid_) {
    00346         // forking failed
    00347
    00348         runs = false;
    00349         free(arglist);
    00350         return false;
    00351   } else {
    00352         if (fd[1])
    00353           close(fd[1]);
    00354         // the parent continues here
    00355
    00356         // Discard any data for stdin that might still be there
    00357         input_data = 0;
    00358
    00359         // Check whether client could be started.
    00360         if (fd[0]) for(;;)
    00361         {
    00362            char resultByte;
    00363            int n = ::read(fd[0], &resultByte, 1);
    00364            if (n == 1)
    00365            {
    00366                // Error
    00367                runs = false;
    00368                close(fd[0]);
    00369                free(arglist);
    00370                pid_ = 0;
    00371                return false;
    00372            }
    00373            if (n == -1)
    00374            {
    00375               if ((errno == ECHILD) || (errno == EINTR))
    00376                  continue; // Ignore
    00377            }
    00378            break; // success
    00379         }
    00380         if (fd[0])
    00381            close(fd[0]);
    00382
    00383         if (!commSetupDoneP())  // finish communication socket setup for the parent
    00384           kdDebug() << "Could not finish comm setup in parent!" << endl;
    00385
    00386         if (run_mode == Block) {
    00387           commClose();
    00388
    00389           // The SIGCHLD handler of the process controller will catch
    00390           // the exit and set the status
    00391           while(runs)
    00392           {
    00393              KProcessController::theKProcessController->
    00394                   waitForProcessExit(10);
    00395           }
    00396           runs = FALSE;
    00397           emit processExited(this);
    00398         }
    00399   }
    00400   free(arglist);
    00401   return true;
    00402 }
    00403
    00404
    00405
    00406 bool KProcess::kill(int signo)
    00407 {
    00408   bool rv=false;
    00409
    00410   if (0 != pid_)
    00411     rv= (-1 != ::kill(pid_, signo));
    00412   // probably store errno somewhere...
    00413   return rv;
    00414 }
    00415
    00416
    00417
    00418 bool KProcess::isRunning() const
    00419 {
    00420   return runs;
    00421 }
    00422
    00423
    00424
    00425 pid_t KProcess::pid() const
    00426 {
    00427   return pid_;
    00428 }
    00429
    00430
    00431
    00432 bool KProcess::normalExit() const
    00433 {
    00434   int _status = status;
    00435   return (pid_ != 0) && (!runs) && (WIFEXITED((_status)));
    00436 }
    00437
    00438
    00439
    00440 int KProcess::exitStatus() const
    00441 {
    00442   int _status = status;
    00443   return WEXITSTATUS((_status));
    00444 }
    00445
    00446
    00447
    00448 bool KProcess::writeStdin(const char *buffer, int buflen)
    00449 {
    00450   bool rv;
    00451
    00452   // if there is still data pending, writing new data
    00453   // to stdout is not allowed (since it could also confuse
    00454   // kprocess...
    00455   if (0 != input_data)
    00456     return false;
    00457
    00458   if (runs && (communication & Stdin)) {
    00459     input_data = buffer;
    00460     input_sent = 0;
    00461     input_total = buflen;
    00462     innot->setEnabled(true);
    00463     if (input_total)
    00464       slotSendData(0);
    00465     rv = true;
    00466   } else
    00467     rv = false;
    00468   return rv;
    00469 }
    00470
    00471 void KProcess::suspend()
    00472 {
    00473   if ((communication & Stdout) && outnot)
    00474      outnot->setEnabled(false);
    00475 }
    00476
    00477 void KProcess::resume()
    00478 {
    00479   if ((communication & Stdout) && outnot)
    00480      outnot->setEnabled(true);
    00481 }
    00482
    00483 bool KProcess::closeStdin()
    00484 {
    00485   bool rv;
    00486
    00487   if (communication & Stdin) {
    00488     communication = (Communication) (communication & ~Stdin);
    00489     delete innot;
    00490     innot = 0;
    00491     close(in[1]);
    00492     rv = true;
    00493   } else
    00494     rv = false;
    00495   return rv;
    00496 }
    00497
    00498 bool KProcess::closeStdout()
    00499 {
    00500   bool rv;
    00501
    00502   if (communication & Stdout) {
    00503     communication = (Communication) (communication & ~Stdout);
    00504     delete outnot;
    00505     outnot = 0;
    00506     close(out[0]);
    00507     rv = true;
    00508   } else
    00509     rv = false;
    00510   return rv;
    00511 }
    00512
    00513 bool KProcess::closeStderr()
    00514 {
    00515   bool rv;
    00516
    00517   if (communication & Stderr) {
    00518     communication = static_cast<Communication>(communication & ~Stderr);
    00519     delete errnot;
    00520     errnot = 0;
    00521     close(err[0]);
    00522     rv = true;
    00523   } else
    00524     rv = false;
    00525   return rv;
    00526 }
    00527
    00528
    00530 // protected slots         //
    00532
    00533
    00534
    00535 void KProcess::slotChildOutput(int fdno)
    00536 {
    00537   if (!childOutput(fdno))
    00538      closeStdout();
    00539 }
    00540
    00541
    00542 void KProcess::slotChildError(int fdno)
    00543 {
    00544   if (!childError(fdno))
    00545      closeStderr();
    00546 }
    00547
    00548
    00549 void KProcess::slotSendData(int)
    00550 {
    00551   if (input_sent == input_total) {
    00552     innot->setEnabled(false);
    00553     input_data = 0;
    00554     emit wroteStdin(this);
    00555   } else
    00556     input_sent += ::write(in[1], input_data+input_sent, input_total-input_sent);
    00557 }
    00558
    00559
    00560
    00562 // private member functions //
    00564
    00565
    00566
    00567 void KProcess::processHasExited(int state)
    00568 {
    00569   if (runs)
    00570   {
    00571     runs = false;
    00572     status = state;
    00573
    00574     commClose(); // cleanup communication sockets
    00575
    00576     // also emit a signal if the process was run Blocking
    00577     if (DontCare != run_mode)
    00578     {
    00579       emit processExited(this);
    00580     }
    00581   }
    00582 }
    00583
    00584
    00585
    00586 int KProcess::childOutput(int fdno)
    00587 {
    00588   if (communication & NoRead) {
    00589      int len = -1;
    00590      emit receivedStdout(fdno, len);
    00591      errno = 0; // Make sure errno doesn't read "EAGAIN"
    00592      return len;
    00593   }
    00594   else
    00595   {
    00596      char buffer[1025];
    00597      int len;
    00598
    00599      len = ::read(fdno, buffer, 1024);
    00600
    00601      if ( 0 < len) {
    00602         buffer[len] = 0; // Just in case.
    00603         emit receivedStdout(this, buffer, len);
    00604      }
    00605      return len;
    00606   }
    00607 }
    00608
    00609
    00610
    00611 int KProcess::childError(int fdno)
    00612 {
    00613   char buffer[1024];
    00614   int len;
    00615
    00616   len = ::read(fdno, buffer, 1024);
    00617
    00618   if ( 0 < len)
    00619         emit receivedStderr(this, buffer, len);
    00620   return len;
    00621 }
    00622
    00623
    00624
    00625 int KProcess::setupCommunication(Communication comm)
    00626 {
    00627   communication = comm;
    00628
    00629   if ((comm & Stdin) && (socketpair(AF_UNIX, SOCK_STREAM, 0, in) < 0))
    00630      comm = (Communication) (comm & ~Stdin);
    00631
    00632   if ((comm & Stdout) && (socketpair(AF_UNIX, SOCK_STREAM, 0, out) < 0))
    00633      comm = (Communication) (comm & ~Stdout);
    00634
    00635   if ((comm & Stderr) && (socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0))
    00636      comm = (Communication) (comm & ~Stderr);
    00637
    00638   if (communication != comm)
    00639   {
    00640      if (comm & Stdin)
    00641      {
    00642         close(in[0]);
    00643         close(in[1]);
    00644      }
    00645      if (comm & Stdout)
    00646      {
    00647         close(out[0]);
    00648         close(out[1]);
    00649      }
    00650      if (comm & Stderr)
    00651      {
    00652         close(err[0]);
    00653         close(err[1]);
    00654      }
    00655      communication = NoCommunication;
    00656      return 0; // Error
    00657   }
    00658
    00659   return 1; // Ok
    00660 }
    00661
    00662
    00663
    00664 int KProcess::commSetupDoneP()
    00665 {
    00666   int ok = 1;
    00667
    00668   if (communication != NoCommunication) {
    00669         if (communication & Stdin)
    00670           close(in[0]);
    00671         if (communication & Stdout)
    00672           close(out[1]);
    00673         if (communication & Stderr)
    00674           close(err[1]);
    00675
    00676         // Don't create socket notifiers and set the sockets non-blocking if
    00677         // blocking is requested.
    00678         if (run_mode == Block) return ok;
    00679
    00680         if (communication & Stdin) {
    00681 //        ok &= (-1 != fcntl(in[1], F_SETFL, O_NONBLOCK));
    00682           innot =  new QSocketNotifier(in[1], QSocketNotifier::Write, this);
    00683           Q_CHECK_PTR(innot);
    00684           innot->setEnabled(false); // will be enabled when data has to be sent
    00685           QObject::connect(innot, SIGNAL(activated(int)),
    00686                                            this, SLOT(slotSendData(int)));
    00687         }
    00688
    00689         if (communication & Stdout) {
    00690 //        ok &= (-1 != fcntl(out[0], F_SETFL, O_NONBLOCK));
    00691           outnot = new QSocketNotifier(out[0], QSocketNotifier::Read, this);
    00692           Q_CHECK_PTR(outnot);
    00693           QObject::connect(outnot, SIGNAL(activated(int)),
    00694                                            this, SLOT(slotChildOutput(int)));
    00695           if (communication & NoRead)
    00696               suspend();
    00697         }
    00698
    00699         if (communication & Stderr) {
    00700 //        ok &= (-1 != fcntl(err[0], F_SETFL, O_NONBLOCK));
    00701           errnot = new QSocketNotifier(err[0], QSocketNotifier::Read, this );
    00702           Q_CHECK_PTR(errnot);
    00703           QObject::connect(errnot, SIGNAL(activated(int)),
    00704                                            this, SLOT(slotChildError(int)));
    00705         }
    00706   }
    00707   return ok;
    00708 }
    00709
    00710
    00711
    00712 int KProcess::commSetupDoneC()
    00713 {
    00714   int ok = 1;
    00715   struct linger so;
    00716   memset(&so, 0, sizeof(so));
    00717
    00718   if (communication & Stdin)
    00719     close(in[1]);
    00720   if (communication & Stdout)
    00721     close(out[0]);
    00722   if (communication & Stderr)
    00723     close(err[0]);
    00724
    00725   if (communication & Stdin)
    00726     ok &= dup2(in[0],  STDIN_FILENO) != -1;
    00727   else {
    00728     int null_fd = open( "/dev/null", O_RDONLY );
    00729     ok &= dup2( null_fd, STDIN_FILENO ) != -1;
    00730     close( null_fd );
    00731   }
    00732   if (communication & Stdout) {
    00733     ok &= dup2(out[1], STDOUT_FILENO) != -1;
    00734     ok &= !setsockopt(out[1], SOL_SOCKET, SO_LINGER, (char*)&so, sizeof(so));
    00735   }
    00736   else {
    00737     int null_fd = open( "/dev/null", O_WRONLY );
    00738     ok &= dup2( null_fd, STDOUT_FILENO ) != -1;
    00739     close( null_fd );
    00740   }
    00741   if (communication & Stderr) {
    00742     ok &= dup2(err[1], STDERR_FILENO) != -1;
    00743     ok &= !setsockopt(err[1], SOL_SOCKET, SO_LINGER, reinterpret_cast<char *>(&so), sizeof(so));
    00744   }
    00745   else {
    00746     int null_fd = open( "/dev/null", O_WRONLY );
    00747     ok &= dup2( null_fd, STDERR_FILENO ) != -1;
    00748     close( null_fd );
    00749   }
    00750   return ok;
    00751 }
    00752
    00753
    00754
    00755 void KProcess::commClose()
    00756 {
    00757   if (NoCommunication != communication) {
    00758         bool b_in = (communication & Stdin);
    00759         bool b_out = (communication & Stdout);
    00760         bool b_err = (communication & Stderr);
    00761         if (b_in)
    00762                 delete innot;
    00763
    00764         if (b_out || b_err) {
    00765           // If both channels are being read we need to make sure that one socket buffer
    00766           // doesn't fill up whilst we are waiting for data on the other (causing a deadlock).
    00767           // Hence we need to use select.
    00768
    00769           // Once one or other of the channels has reached EOF (or given an error) go back
    00770           // to the usual mechanism.
    00771
    00772           int fds_ready = 1;
    00773           fd_set rfds;
    00774
    00775           int max_fd = 0;
    00776           if (b_out) {
    00777             fcntl(out[0], F_SETFL, O_NONBLOCK);
    00778             if (out[0] > max_fd)
    00779               max_fd = out[0];
    00780             delete outnot;
    00781             outnot = 0;
    00782           }
    00783           if (b_err) {
    00784             fcntl(err[0], F_SETFL, O_NONBLOCK);
    00785             if (err[0] > max_fd)
    00786               max_fd = err[0];
    00787             delete errnot;
    00788             errnot = 0;
    00789           }
    00790
    00791
    00792           while (b_out || b_err) {
    00793             // * If the process is still running we block until we
    00794             // receive data. (p_timeout = 0, no timeout)
    00795             // * If the process has already exited, we only check
    00796             // the available data, we don't wait for more.
    00797             // (p_timeout = &timeout, timeout immediately)
    00798             struct timeval timeout;
    00799             timeout.tv_sec = 0;
    00800             timeout.tv_usec = 0;
    00801             struct timeval *p_timeout = runs ? 0 : &timeout;
    00802
    00803             FD_ZERO(&rfds);
    00804             if (b_out)
    00805               FD_SET(out[0], &rfds);
    00806
    00807             if (b_err)
    00808               FD_SET(err[0], &rfds);
    00809
    00810             fds_ready = select(max_fd+1, &rfds, 0, 0, p_timeout);
    00811             if (fds_ready <= 0) break;
    00812
    00813             if (b_out && FD_ISSET(out[0], &rfds)) {
    00814               int ret = 1;
    00815               while (ret > 0) ret = childOutput(out[0]);
    00816               if ((ret == -1 && errno != EAGAIN) || ret == 0)
    00817                  b_out = false;
    00818             }
    00819
    00820             if (b_err && FD_ISSET(err[0], &rfds)) {
    00821               int ret = 1;
    00822               while (ret > 0) ret = childError(err[0]);
    00823               if ((ret == -1 && errno != EAGAIN) || ret == 0)
    00824                  b_err = false;
    00825             }
    00826           }
    00827         }
    00828
    00829         if (communication & Stdin) {
    00830             communication = (Communication) (communication & ~Stdin);
    00831             close(in[1]);
    00832         }
    00833         if (communication & Stdout) {
    00834             communication = (Communication) (communication & ~Stdout);
    00835             close(out[0]);
    00836         }
    00837         if (communication & Stderr) {
    00838             communication = (Communication) (communication & ~Stderr);
    00839             close(err[0]);
    00840         }
    00841   }
    00842 }
    00843
    00844 void KProcess::setUseShell(bool useShell, const char *shell)
    00845 {
    00846   if (!d)
    00847     d = new KProcessPrivate;
    00848   d->useShell = useShell;
    00849   d->shell = shell;
    00850   if (d->shell.isEmpty())
    00851      d->shell = searchShell();
    00852 }
    00853
    00854 QString KProcess::quote(const QString &arg)
    00855 {
    00856     QString res = arg;
    00857     res.replace(QRegExp(QString::fromLatin1("\'")),
    00858                 QString::fromLatin1("'\"'\"'"));
    00859     res.prepend('\'');
    00860     res.append('\'');
    00861     return res;
    00862 }
    00863
    00864 QCString KProcess::searchShell()
    00865 {
    00866   QCString tmpShell = QCString(getenv("SHELL")).stripWhiteSpace();
    00867   if (!isExecutable(tmpShell))
    00868   {
    00869      tmpShell = "/bin/sh";
    00870   }
    00871
    00872   return tmpShell;
    00873 }
    00874
    00875 bool KProcess::isExecutable(const QCString &filename)
    00876 {
    00877   struct stat fileinfo;
    00878
    00879   if (filename.isEmpty()) return false;
    00880
    00881   // CC: we've got a valid filename, now let's see whether we can execute that file
    00882
    00883   if (-1 == stat(filename.data(), &fileinfo)) return false;
    00884   // CC: return false if the file does not exist
    00885
    00886   // CC: anyway, we cannot execute directories, block/character devices, fifos or sockets
    00887   if ( (S_ISDIR(fileinfo.st_mode))  ||
    00888        (S_ISCHR(fileinfo.st_mode))  ||
    00889        (S_ISBLK(fileinfo.st_mode))  ||
    00890 #ifdef S_ISSOCK
    00891        // CC: SYSVR4 systems don't have that macro
    00892        (S_ISSOCK(fileinfo.st_mode)) ||
    00893 #endif
    00894        (S_ISFIFO(fileinfo.st_mode)) ||
    00895        (S_ISDIR(fileinfo.st_mode)) ) {
    00896     return false;
    00897   }
    00898
    00899   // CC: now check for permission to execute the file
    00900   if (access(filename.data(), X_OK) != 0) return false;
    00901
    00902   // CC: we've passed all the tests...
    00903   return true;
    00904 }
    00905
    00906 void KProcess::virtual_hook( int, void* )
    00907 { /*BASE::virtual_hook( id, data );*/ }
    00908
    00909
    00911 // CC: Class KShellProcess
    00913
    00914 KShellProcess::KShellProcess(const char *shellname):
    00915   KProcess()
    00916 {
    00917   setUseShell(true, shellname);
    00918 }
    00919
    00920
    00921 KShellProcess::~KShellProcess() {
    00922 }
    00923
    00924 QString KShellProcess::quote(const QString &arg)
    00925 {
    00926     return KProcess::quote(arg);
    00927 }
    00928
    00929 bool KShellProcess::start(RunMode runmode, Communication comm)
    00930 {
    00931   return KProcess::start(runmode, comm);
    00932 }
    00933
    00934 void KShellProcess::virtual_hook( int id, void* data )
    00935 { KProcess::virtual_hook( id, data ); }
    00936
    00937 #include "kprocess.moc"

This file is part of the documentation for kdelibs Version 3.1.5.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Jan 28 12:46:47 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001