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

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