kdecore Library API Documentation

kprocess.cpp

00001 /*
00002 
00003    $Id: kprocess.cpp,v 1.88.2.2 2002/12/19 10:49:44 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     slotSendData(0);
00463     innot->setEnabled(true);
00464     rv = true;
00465   } else
00466     rv = false;
00467   return rv;
00468 }
00469 
00470 void KProcess::suspend()
00471 {
00472   if ((communication & Stdout) && outnot)
00473      outnot->setEnabled(false);
00474 }
00475 
00476 void KProcess::resume()
00477 {
00478   if ((communication & Stdout) && outnot)
00479      outnot->setEnabled(true);
00480 }
00481 
00482 bool KProcess::closeStdin()
00483 {
00484   bool rv;
00485 
00486   if (communication & Stdin) {
00487     communication = (Communication) (communication & ~Stdin);
00488     delete innot;
00489     innot = 0;
00490     close(in[1]);
00491     rv = true;
00492   } else
00493     rv = false;
00494   return rv;
00495 }
00496 
00497 bool KProcess::closeStdout()
00498 {
00499   bool rv;
00500 
00501   if (communication & Stdout) {
00502     communication = (Communication) (communication & ~Stdout);
00503     delete outnot;
00504     outnot = 0;
00505     close(out[0]);
00506     rv = true;
00507   } else
00508     rv = false;
00509   return rv;
00510 }
00511 
00512 bool KProcess::closeStderr()
00513 {
00514   bool rv;
00515 
00516   if (communication & Stderr) {
00517     communication = static_cast<Communication>(communication & ~Stderr);
00518     delete errnot;
00519     errnot = 0;
00520     close(err[0]);
00521     rv = true;
00522   } else
00523     rv = false;
00524   return rv;
00525 }
00526 
00527 
00529 // protected slots         //
00531 
00532 
00533 
00534 void KProcess::slotChildOutput(int fdno)
00535 {
00536   if (!childOutput(fdno))
00537      closeStdout();
00538 }
00539 
00540 
00541 void KProcess::slotChildError(int fdno)
00542 {
00543   if (!childError(fdno))
00544      closeStderr();
00545 }
00546 
00547 
00548 void KProcess::slotSendData(int)
00549 {
00550   if (input_sent == input_total) {
00551     innot->setEnabled(false);
00552     input_data = 0;
00553     emit wroteStdin(this);
00554   } else
00555     input_sent += ::write(in[1], input_data+input_sent, input_total-input_sent);
00556 }
00557 
00558 
00559 
00561 // private member functions //
00563 
00564 
00565 
00566 void KProcess::processHasExited(int state)
00567 {
00568   if (runs)
00569   {
00570     runs = false;
00571     status = state;
00572 
00573     commClose(); // cleanup communication sockets
00574 
00575     // also emit a signal if the process was run Blocking
00576     if (DontCare != run_mode)
00577     {
00578       emit processExited(this);
00579     }
00580   }
00581 }
00582 
00583 
00584 
00585 int KProcess::childOutput(int fdno)
00586 {
00587   if (communication & NoRead) {
00588      int len = -1;
00589      emit receivedStdout(fdno, len);
00590      errno = 0; // Make sure errno doesn't read "EAGAIN"
00591      return len;
00592   }
00593   else
00594   {
00595      char buffer[1025];
00596      int len;
00597 
00598      len = ::read(fdno, buffer, 1024);
00599      
00600      if ( 0 < len) {
00601         buffer[len] = 0; // Just in case.
00602         emit receivedStdout(this, buffer, len);
00603      }
00604      return len;
00605   }
00606 }
00607 
00608 
00609 
00610 int KProcess::childError(int fdno)
00611 {
00612   char buffer[1024];
00613   int len;
00614 
00615   len = ::read(fdno, buffer, 1024);
00616 
00617   if ( 0 < len)
00618         emit receivedStderr(this, buffer, len);
00619   return len;
00620 }
00621 
00622 
00623 
00624 int KProcess::setupCommunication(Communication comm)
00625 {
00626   communication = comm;
00627 
00628   if ((comm & Stdin) && (socketpair(AF_UNIX, SOCK_STREAM, 0, in) < 0))
00629      comm = (Communication) (comm & ~Stdin);
00630 
00631   if ((comm & Stdout) && (socketpair(AF_UNIX, SOCK_STREAM, 0, out) < 0))
00632      comm = (Communication) (comm & ~Stdout);
00633 
00634   if ((comm & Stderr) && (socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0))
00635      comm = (Communication) (comm & ~Stderr);
00636   
00637   if (communication != comm)
00638   {
00639      if (comm & Stdin)
00640      {
00641         close(in[0]);
00642         close(in[1]);        
00643      }
00644      if (comm & Stdout)
00645      {
00646         close(out[0]);
00647         close(out[1]);        
00648      }
00649      if (comm & Stderr)
00650      {
00651         close(err[0]);
00652         close(err[1]);        
00653      }
00654      communication = NoCommunication;
00655      return 0; // Error
00656   }
00657 
00658   return 1; // Ok
00659 }
00660 
00661 
00662 
00663 int KProcess::commSetupDoneP()
00664 {
00665   int ok = 1;
00666 
00667   if (communication != NoCommunication) {
00668         if (communication & Stdin)
00669           close(in[0]);
00670         if (communication & Stdout)
00671           close(out[1]);
00672         if (communication & Stderr)
00673           close(err[1]);
00674 
00675         // Don't create socket notifiers and set the sockets non-blocking if
00676         // blocking is requested.
00677         if (run_mode == Block) return ok;
00678 
00679         if (communication & Stdin) {
00680 //        ok &= (-1 != fcntl(in[1], F_SETFL, O_NONBLOCK));
00681           innot =  new QSocketNotifier(in[1], QSocketNotifier::Write, this);
00682           Q_CHECK_PTR(innot);
00683           innot->setEnabled(false); // will be enabled when data has to be sent
00684           QObject::connect(innot, SIGNAL(activated(int)),
00685                                            this, SLOT(slotSendData(int)));
00686         }
00687 
00688         if (communication & Stdout) {
00689 //        ok &= (-1 != fcntl(out[0], F_SETFL, O_NONBLOCK));
00690           outnot = new QSocketNotifier(out[0], QSocketNotifier::Read, this);
00691           Q_CHECK_PTR(outnot);
00692           QObject::connect(outnot, SIGNAL(activated(int)),
00693                                            this, SLOT(slotChildOutput(int)));
00694           if (communication & NoRead)
00695               suspend();
00696         }
00697 
00698         if (communication & Stderr) {
00699 //        ok &= (-1 != fcntl(err[0], F_SETFL, O_NONBLOCK));
00700           errnot = new QSocketNotifier(err[0], QSocketNotifier::Read, this );
00701           Q_CHECK_PTR(errnot);
00702           QObject::connect(errnot, SIGNAL(activated(int)),
00703                                            this, SLOT(slotChildError(int)));
00704         }
00705   }
00706   return ok;
00707 }
00708 
00709 
00710 
00711 int KProcess::commSetupDoneC()
00712 {
00713   int ok = 1;
00714   struct linger so;
00715   memset(&so, 0, sizeof(so));
00716 
00717   if (communication & Stdin)
00718     close(in[1]);
00719   if (communication & Stdout)
00720     close(out[0]);
00721   if (communication & Stderr)
00722     close(err[0]);
00723 
00724   if (communication & Stdin)
00725     ok &= dup2(in[0],  STDIN_FILENO) != -1;
00726   else {
00727     int null_fd = open( "/dev/null", O_RDONLY );
00728     ok &= dup2( null_fd, STDIN_FILENO ) != -1;
00729     close( null_fd );
00730   }
00731   if (communication & Stdout) {
00732     ok &= dup2(out[1], STDOUT_FILENO) != -1;
00733     ok &= !setsockopt(out[1], SOL_SOCKET, SO_LINGER, (char*)&so, sizeof(so));
00734   }
00735   else {
00736     int null_fd = open( "/dev/null", O_WRONLY );
00737     ok &= dup2( null_fd, STDOUT_FILENO ) != -1;
00738     close( null_fd );
00739   }
00740   if (communication & Stderr) {
00741     ok &= dup2(err[1], STDERR_FILENO) != -1;
00742     ok &= !setsockopt(err[1], SOL_SOCKET, SO_LINGER, reinterpret_cast<char *>(&so), sizeof(so));
00743   }
00744   else {
00745     int null_fd = open( "/dev/null", O_WRONLY );
00746     ok &= dup2( null_fd, STDERR_FILENO ) != -1;
00747     close( null_fd );
00748   }
00749   return ok;
00750 }
00751 
00752 
00753 
00754 void KProcess::commClose()
00755 {
00756   if (NoCommunication != communication) {
00757         bool b_in = (communication & Stdin);
00758         bool b_out = (communication & Stdout);
00759         bool b_err = (communication & Stderr);
00760         if (b_in)
00761                 delete innot;
00762 
00763         if (b_out || b_err) {
00764           // If both channels are being read we need to make sure that one socket buffer
00765           // doesn't fill up whilst we are waiting for data on the other (causing a deadlock).
00766           // Hence we need to use select.
00767 
00768           // Once one or other of the channels has reached EOF (or given an error) go back
00769           // to the usual mechanism.
00770 
00771           int fds_ready = 1;
00772           fd_set rfds;
00773 
00774           int max_fd = 0;
00775           if (b_out) {
00776             fcntl(out[0], F_SETFL, O_NONBLOCK);
00777             if (out[0] > max_fd)
00778               max_fd = out[0];
00779             delete outnot;
00780             outnot = 0;
00781           }
00782           if (b_err) {
00783             fcntl(err[0], F_SETFL, O_NONBLOCK);
00784             if (err[0] > max_fd)
00785               max_fd = err[0];
00786             delete errnot;
00787             errnot = 0;
00788           }
00789 
00790 
00791           while (b_out || b_err) {
00792             // * If the process is still running we block until we
00793             // receive data. (p_timeout = 0, no timeout)
00794             // * If the process has already exited, we only check
00795             // the available data, we don't wait for more.
00796             // (p_timeout = &timeout, timeout immediately)
00797             struct timeval timeout;
00798             timeout.tv_sec = 0;
00799             timeout.tv_usec = 0;
00800             struct timeval *p_timeout = runs ? 0 : &timeout;
00801 
00802             FD_ZERO(&rfds);
00803             if (b_out)
00804               FD_SET(out[0], &rfds);
00805 
00806             if (b_err)
00807               FD_SET(err[0], &rfds);
00808 
00809             fds_ready = select(max_fd+1, &rfds, 0, 0, p_timeout);
00810             if (fds_ready <= 0) break;
00811 
00812             if (b_out && FD_ISSET(out[0], &rfds)) {
00813               int ret = 1;
00814               while (ret > 0) ret = childOutput(out[0]);
00815               if ((ret == -1 && errno != EAGAIN) || ret == 0)
00816                  b_out = false;
00817             }
00818 
00819             if (b_err && FD_ISSET(err[0], &rfds)) {
00820               int ret = 1;
00821               while (ret > 0) ret = childError(err[0]);
00822               if ((ret == -1 && errno != EAGAIN) || ret == 0)
00823                  b_err = false;
00824             }
00825           }
00826         }
00827 
00828         if (communication & Stdin) {
00829         communication = (Communication) (communication & ~Stdin);
00830             close(in[1]);
00831         }
00832         if (communication & Stdout) {
00833         communication = (Communication) (communication & ~Stdout);
00834             close(out[0]);
00835         }
00836         if (communication & Stderr) {
00837         communication = (Communication) (communication & ~Stderr);
00838             close(err[0]);
00839         }
00840   }
00841 }
00842 
00843 void KProcess::setUseShell(bool useShell, const char *shell)
00844 {
00845   if (!d)
00846     d = new KProcessPrivate;
00847   d->useShell = useShell;
00848   d->shell = shell;
00849   if (d->shell.isEmpty())
00850      d->shell = searchShell();
00851 }
00852 
00853 QString KProcess::quote(const QString &arg)
00854 {
00855     QString res = arg;
00856     res.replace(QRegExp(QString::fromLatin1("\'")),
00857                 QString::fromLatin1("'\"'\"'"));
00858     res.prepend('\'');
00859     res.append('\'');
00860     return res;
00861 }
00862 
00863 QCString KProcess::searchShell()
00864 {
00865   QCString tmpShell = QCString(getenv("SHELL")).stripWhiteSpace();
00866   if (!isExecutable(tmpShell))
00867   {
00868      tmpShell = "/bin/sh";
00869   }
00870 
00871   return tmpShell;
00872 }
00873 
00874 bool KProcess::isExecutable(const QCString &filename)
00875 {
00876   struct stat fileinfo;
00877 
00878   if (filename.isEmpty()) return false;
00879 
00880   // CC: we've got a valid filename, now let's see whether we can execute that file
00881 
00882   if (-1 == stat(filename.data(), &fileinfo)) return false;
00883   // CC: return false if the file does not exist
00884 
00885   // CC: anyway, we cannot execute directories, block/character devices, fifos or sockets
00886   if ( (S_ISDIR(fileinfo.st_mode))  ||
00887        (S_ISCHR(fileinfo.st_mode))  ||
00888        (S_ISBLK(fileinfo.st_mode))  ||
00889 #ifdef S_ISSOCK
00890        // CC: SYSVR4 systems don't have that macro
00891        (S_ISSOCK(fileinfo.st_mode)) ||
00892 #endif
00893        (S_ISFIFO(fileinfo.st_mode)) ||
00894        (S_ISDIR(fileinfo.st_mode)) ) {
00895     return false;
00896   }
00897 
00898   // CC: now check for permission to execute the file
00899   if (access(filename.data(), X_OK) != 0) return false;
00900 
00901   // CC: we've passed all the tests...
00902   return true;
00903 }
00904 
00905 void KProcess::virtual_hook( int, void* )
00906 { /*BASE::virtual_hook( id, data );*/ }
00907 
00908 
00910 // CC: Class KShellProcess
00912 
00913 KShellProcess::KShellProcess(const char *shellname):
00914   KProcess()
00915 {
00916   setUseShell(true, shellname);
00917 }
00918 
00919 
00920 KShellProcess::~KShellProcess() {
00921 }
00922 
00923 QString KShellProcess::quote(const QString &arg)
00924 {
00925     return KProcess::quote(arg);
00926 }
00927 
00928 bool KShellProcess::start(RunMode runmode, Communication comm)
00929 {
00930   return KProcess::start(runmode, comm);
00931 }
00932 
00933 void KShellProcess::virtual_hook( int id, void* data )
00934 { KProcess::virtual_hook( id, data ); }
00935 
00936 #include "kprocess.moc"
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:20:41 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001