Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

oprocess.cpp

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

Generated on Sat Nov 5 16:16:10 2005 for OPIE by  doxygen 1.4.2