kdecore Library API Documentation

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"
KDE Logo
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