libopie API Documentation

oprocess.cpp

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