2004-08-28 16:21:25 +00:00
/** @file
$Id$
$Date$
$Author$
@copy © Marc Wäckerlin
@license LGPL, see file <a href="license.html">COPYING</a>
$Log$
2005-04-19 18:48:00 +00:00
Revision 1.11 2005/04/19 18:48:00 marc
new feature PartialExec
2005-03-14 16:26:34 +00:00
Revision 1.10 2005/03/14 16:26:34 marc
bugs have been fixed a long time ago, now no more in buglist
2004-12-20 07:40:36 +00:00
Revision 1.9 2004/12/20 07:40:35 marc
documentation improved, new grouping
2004-12-18 21:00:09 +00:00
Revision 1.8 2004/12/18 21:00:09 marc
everything is ok, when pipes are non blocking on parent's side and blocking on client's side, and select is not used (not necessary for non blocking IO)
2004-12-17 17:38:57 +00:00
Revision 1.7 2004/12/17 17:38:57 marc
it works perfectly with blocking pipes and buffer size of 1
2004-12-17 16:28:51 +00:00
Revision 1.6 2004/12/17 16:28:51 marc
stable implementation with select for both executes
2004-12-14 20:30:10 +00:00
Revision 1.5 2004/12/14 20:30:09 marc
added possibility to pass string to stdin of child process
2004-08-28 16:21:25 +00:00
Revision 1.4 2004/08/28 16:21:25 marc
mrw-c++-0.92 (mrw)
- new file: version.cpp
- new file header for all sources
- work around warning in mrw::auto<T>
- possibility to compile without log4cxx
- work around bugs in demangle.h and libiberty.h
- corrections in documentation
- added simple tracing mechanism
- more warnings
- small corrections in Auto<>::Free and a new test for it
- possibility to compile without stack trace
*/
2004-04-21 06:39:20 +00:00
#include <mrw/exec.hpp>
#include <mrw/unistd.hpp>
2004-08-28 16:21:25 +00:00
#include <mrw/exception.hpp>
2004-12-20 07:40:36 +00:00
#include <sys/wait.h> // waitpid
#include <unistd.h> // fork, exec
2004-12-18 21:00:09 +00:00
#include <string.h> // memcpy
2004-12-14 20:30:10 +00:00
#include <assert.h> // assert
2005-04-19 18:48:00 +00:00
#include <sys/types.h> // kill
#include <signal.h> // kill
2004-04-21 06:39:20 +00:00
2005-04-19 18:48:00 +00:00
//=========================================================== ExecutionFailedExc
//------------------------------------------------------------------------------
2004-04-21 06:39:20 +00:00
mrw :: ExecutionFailedExc :: ExecutionFailedExc ( const std :: string & w ,
const std :: string & c )
throw ( std :: bad_exception ) :
_what ( std :: string ( "mrw::Exec: command execution failed \n " ) +
std :: string ( " failed command was: \" " + c + " \"\n " ) +
std :: string ( " error was: \" " ) + w + '"' ) {
/**
@c what looks like:
@verbatim
mrw::Exec: command execution failed
failed command was: "/bin/OOOOPS -v -q --crash"
error was: "execution failed"
@endverbatim
*/
}
2005-04-19 18:48:00 +00:00
//========================================================================== Cmd
//------------------------------------------------------------------------------
2004-04-21 06:39:20 +00:00
mrw :: Cmd :: Cmd ( const std :: string & c ) throw ( std :: bad_exception ) {
_cmd . push_back ( c );
}
2005-04-19 18:48:00 +00:00
//------------------------------------------------------------------------------
2004-04-21 06:39:20 +00:00
mrw :: Cmd & mrw :: Cmd :: operator ,( const std :: string & arg )
throw ( std :: bad_exception ) {
_cmd . push_back ( arg );
return * this ;
}
2005-04-19 18:48:00 +00:00
//------------------------------------------------------------------------------
2004-04-21 06:39:20 +00:00
mrw :: Cmd & mrw :: Cmd :: operator << ( const std :: string & arg )
throw ( std :: bad_exception ) {
_cmd . push_back ( arg );
return * this ;
}
2005-04-19 18:48:00 +00:00
//------------------------------------------------------------------------------
2004-04-21 06:39:20 +00:00
mrw :: Cmd :: operator std :: string () const throw ( std :: bad_exception ) {
ArgList :: const_iterator it ( _cmd . begin ());
std :: string c ( * it );
while ( ++ it != _cmd . end ()) c += ' ' +* it ;
return c ;
}
2005-04-19 18:48:00 +00:00
//------------------------------------------------------------------------------
2004-04-21 06:39:20 +00:00
mrw :: Cmd :: operator mrw :: Exec () const throw ( std :: bad_exception ) {
return mrw :: Exec ( * this );
}
2005-04-19 18:48:00 +00:00
//------------------------------------------------------------------------------
mrw :: Cmd :: operator mrw :: PartialExec () const throw ( std :: bad_exception ) {
return mrw :: PartialExec ( * this );
}
//------------------------------------------------------------------------------
2004-12-14 20:30:10 +00:00
mrw :: Exec mrw :: Cmd :: execute ( bool exc ) const throw ( std :: exception ) {
return mrw :: Exec ( * this ). execute ( exc );
}
2005-04-19 18:48:00 +00:00
//------------------------------------------------------------------------------
2004-12-14 20:30:10 +00:00
mrw :: Exec mrw :: Cmd :: execute ( const std :: string & input , bool exc ) const
throw ( std :: exception ) {
return mrw :: Exec ( * this ). execute ( input , exc );
2004-04-21 06:39:20 +00:00
}
2005-04-19 18:48:00 +00:00
//------------------------------------------------------------------------------
mrw :: PartialExec mrw :: Cmd :: start ( bool useInput ) const throw ( std :: exception ) {
return mrw :: PartialExec ( * this ). start ( useInput );
}
//------------------------------------------------------------------------------
2004-04-21 06:39:20 +00:00
const char * mrw :: Cmd :: path () const throw ( std :: bad_exception ) {
return _cmd . front (). c_str ();
}
2005-04-19 18:48:00 +00:00
//------------------------------------------------------------------------------
2004-04-21 06:39:20 +00:00
char ** mrw :: Cmd :: args () const throw ( std :: bad_exception ) {
if ( _cmd . size () == 0 ) return 0 ;
char ** array = new char * [ _cmd . size () + 1 ];
int i ( 0 );
for ( ArgList :: const_iterator it ( _cmd . begin ()); it != _cmd . end (); ++ it )
memcpy ( array [ i ++ ] = new char [ it -> size () + 1 ], it -> c_str (), it -> size () + 1 );
array [ i ] = 0 ;
return array ;
}
2005-04-19 18:48:00 +00:00
//========================================================================= Exec
//------------------------------------------------------------------------------
2004-04-21 06:39:20 +00:00
mrw :: Exec :: Exec ( const mrw :: Cmd & c ) throw ( std :: bad_exception ) :
_cmd ( new mrw :: Cmd ( c )), _success ( false ) {
}
2005-04-19 18:48:00 +00:00
//------------------------------------------------------------------------------
2004-04-21 06:39:20 +00:00
mrw :: Exec :: Exec ( const mrw :: Exec & e ) throw ( std :: bad_exception ) :
_cmd ( new mrw :: Cmd ( * e . _cmd )),
_res ( e . _res ), _err ( e . _err ), _success ( e . _success ) {
}
2005-04-19 18:48:00 +00:00
//------------------------------------------------------------------------------
2004-04-21 06:39:20 +00:00
mrw :: Exec ::~ Exec () throw () {
delete _cmd ;
}
2005-04-19 18:48:00 +00:00
//------------------------------------------------------------------------------
2004-04-21 06:39:20 +00:00
mrw :: Exec & mrw :: Exec :: operator = ( const mrw :: Exec & e ) throw ( std :: bad_exception ) {
if ( this ==& e ) return * this ;
* _cmd =* e . _cmd ; _res = e . _res ; _err = e . _err ; _success = e . _success ;
return * this ;
}
2005-04-19 18:48:00 +00:00
//------------------------------------------------------------------------------
2004-12-14 20:30:10 +00:00
mrw :: Exec & mrw :: Exec :: execute ( bool exc ) throw ( std :: exception ) {
2004-04-21 06:39:20 +00:00
/** This method calls @c fork, sets up a pipe connection to pass @c
2004-12-14 20:30:10 +00:00
stdout and @c stderr from the child process to the parent
process using mrw::Pipe and calls @c execvp to execute the
program. */
2004-04-21 06:39:20 +00:00
_success = false ;
_res = _err = "" ;
2004-12-18 21:00:09 +00:00
mrw :: Pipe stdOut ( mrw :: Pipe :: block_output ), stdErr ( mrw :: Pipe :: block_output );
2004-04-23 16:03:29 +00:00
if ( ! stdOut || ! stdErr )
2004-04-21 06:39:20 +00:00
throw mrw :: ExecutionFailedExc ( "cannot create pipe" , * _cmd );
pid_t pid ( fork ());
if ( pid < 0 )
throw ExecutionFailedExc ( "cannot fork" , * _cmd );
if ( pid ) { // parent
2004-04-23 16:03:29 +00:00
stdOut . close_out ();
stdErr . close_out ();
if ( ! stdOut || ! stdErr )
2004-04-21 06:39:20 +00:00
throw ExecutionFailedExc ( "cannot close pipe" , * _cmd );
2004-12-18 21:00:09 +00:00
ssize_t num1 ( 1 ), num2 ( 1 );
char buf [ 4096 ];
2004-12-17 16:28:51 +00:00
int res ( 0 ), s ( 0 );
2005-03-14 16:26:34 +00:00
/* It sometimes did not get the whole input since I changed to non
blocking pipes. Now I have found the solution to the problems:
Non blocking IO does not work in conjunction with select!
Also the pipe must not be nonblocking on both ends, but only on
one. */
2004-12-18 21:00:09 +00:00
while ( num1 || num2 ||! res ) try { // not end of files or child terminated
2004-12-17 16:28:51 +00:00
if ( ! res && ( res = waitpid ( pid , & s , WNOHANG )))
if ( res != pid || WIFEXITED ( s ) != 0 && WEXITSTATUS ( s ) != 0 )
throw ExecutionFailedExc ( "execution failed" , * _cmd );
2004-12-18 21:00:09 +00:00
if ( num1 <= 0 && num2 <= 0 ) usleep ( 10000 ); // nothing to read last time
2004-12-17 16:28:51 +00:00
// check and handle stdout
2004-12-18 21:00:09 +00:00
if ( num1 && ( num1 = read ( stdOut . istream (), buf , sizeof ( buf ))) > 0 )
_res += std :: string ( buf , num1 );
2005-04-19 18:48:00 +00:00
else if ( num1 ==- 1 )
if ( errno != EINTR && errno != EAGAIN )
throw ExecutionFailedExc ( "readin stdout" , * _cmd );
else
num1 = 1 ;
2004-12-17 16:28:51 +00:00
// check and handle stderr
2004-12-18 21:00:09 +00:00
if ( num2 && ( num2 = read ( stdErr . istream (), buf , sizeof ( buf ))) > 0 )
_err += std :: string ( buf , num2 );
2005-04-19 18:48:00 +00:00
else if ( num2 ==- 1 )
if ( errno != EINTR && errno != EAGAIN )
throw ExecutionFailedExc ( "readin stderr" , * _cmd );
else
num2 = 1 ;
2004-12-17 16:28:51 +00:00
} catch (...) {
_success = false ;
2005-04-19 18:48:00 +00:00
if ( exc ) throw ;
2004-12-17 16:28:51 +00:00
return * this ;
2004-04-21 06:39:20 +00:00
}
} else { // child
2004-04-23 16:03:29 +00:00
stdOut . close_in ();
stdErr . close_in ();
stdOut . connect_cout ();
stdErr . connect_cerr ();
2004-04-21 06:39:20 +00:00
execvp ( _cmd -> path (), _cmd -> args ());
exit ( 1 ); // execute failed
}
_success = true ;
return * this ;
}
2005-04-19 18:48:00 +00:00
//------------------------------------------------------------------------------
2004-12-14 20:30:10 +00:00
mrw :: Exec & mrw :: Exec :: execute ( const std :: string & input , bool exc )
throw ( std :: exception ) {
/// @c input length must be smaller than @c SSIZE_MAX.
/// I'll only add support for longer strings upon request.
assert ( input . size () <= SSIZE_MAX &&
"sdin input exeeds C library limit in mrw::Exec "
"please contact the author of the library" );
/** This method calls @c fork, sets up a pipe connection to pass @c
2005-04-19 18:48:00 +00:00
stdin, @c stdout and @c stderr between the child process and the
2004-12-14 20:30:10 +00:00
parent process using mrw::Pipe and calls @c execvp to execute
the program. */
_success = false ;
_res = _err = "" ;
2004-12-18 21:00:09 +00:00
mrw :: Pipe stdIn ( mrw :: Pipe :: block_input ),
stdOut ( mrw :: Pipe :: block_output ), stdErr ( mrw :: Pipe :: block_output );
2004-12-14 20:30:10 +00:00
if ( ! stdIn || ! stdOut || ! stdErr )
throw mrw :: ExecutionFailedExc ( "cannot create pipe" , * _cmd );
pid_t pid ( fork ());
if ( pid < 0 ) throw ExecutionFailedExc ( "cannot fork" , * _cmd );
if ( pid ) { // parent
stdIn . close_in ();
stdOut . close_out ();
stdErr . close_out ();
if ( ! stdIn || ! stdOut || ! stdErr )
throw ExecutionFailedExc ( "cannot close pipes" , * _cmd );
2004-12-18 21:00:09 +00:00
ssize_t num0 ( 1 ), num1 ( 1 ), num2 ( 1 );
2004-12-14 20:30:10 +00:00
std :: string in ( input );
2004-12-18 21:00:09 +00:00
char buf [ 4096 ];
2004-12-17 16:28:51 +00:00
int res ( 0 ), s ( 0 );
2005-03-14 16:26:34 +00:00
/* It sometimes did not get the whole input since I changed to non
blocking pipes. Now I have found the solution to the problems:
Non blocking IO does not work in conjunction with select! Also
the pipe must not be nonblocking on both ends, but only on
one. */
2004-12-18 21:00:09 +00:00
while ( num0 || num1 || num2 ||! res ) try { // not end of files or child terminated
2004-12-17 16:28:51 +00:00
if ( ! res && ( res = waitpid ( pid , & s , WNOHANG )))
2004-12-14 20:30:10 +00:00
if ( res != pid || WIFEXITED ( s ) != 0 && WEXITSTATUS ( s ) != 0 )
throw ExecutionFailedExc ( "execution failed" , * _cmd );
2004-12-18 21:00:09 +00:00
if ( num0 <= 0 && num1 <= 0 && num2 <= 0 ) usleep ( 10000 ); // no activity last time
2004-12-14 20:30:10 +00:00
// check and handle stdin
2004-12-18 21:00:09 +00:00
if ( num0 && ( num0 = write ( stdIn . ostream (), in . c_str (), in . size ())) > 0 ) {
if (( unsigned int ) num0 < in . size ())
in = in . substr ( num0 );
else if (( unsigned int ) num0 == in . size ())
num0 = 0 , stdIn . close_out ();
2005-04-19 18:48:00 +00:00
} else if ( num0 ==- 1 )
if ( errno != EINTR && errno != EAGAIN )
throw ExecutionFailedExc ( "writing stdin" , * _cmd );
else
num0 = 1 ;
2004-12-14 20:30:10 +00:00
// check and handle stdout
2004-12-18 21:00:09 +00:00
if ( num1 && ( num1 = read ( stdOut . istream (), buf , sizeof ( buf ))) > 0 )
_res += std :: string ( buf , num1 );
2005-04-19 18:48:00 +00:00
else if ( num1 ==- 1 )
if ( errno != EINTR && errno != EAGAIN )
throw ExecutionFailedExc ( "readin stdout" , * _cmd );
else
num1 = 1 ;
2004-12-14 20:30:10 +00:00
// check and handle stderr
2004-12-18 21:00:09 +00:00
if ( num2 && ( num2 = read ( stdErr . istream (), buf , sizeof ( buf ))) > 0 )
_err += std :: string ( buf , num2 );
2005-04-19 18:48:00 +00:00
else if ( num2 ==- 1 )
if ( errno != EINTR && errno != EAGAIN )
throw ExecutionFailedExc ( "readin stderr" , * _cmd );
else
num2 = 1 ;
2004-12-14 20:30:10 +00:00
} catch (...) {
_success = false ;
2005-04-19 18:48:00 +00:00
if ( exc ) throw ;
2004-12-14 20:30:10 +00:00
return * this ;
}
} else { // child
stdIn . close_out ();
stdOut . close_in ();
stdErr . close_in ();
stdIn . connect_cin ();
2004-12-20 07:40:36 +00:00
stdOut . connect_cout ();
2004-12-14 20:30:10 +00:00
stdErr . connect_cerr ();
execvp ( _cmd -> path (), _cmd -> args ());
exit ( 1 ); // execute failed
}
_success = true ;
return * this ;
}
2005-04-19 18:48:00 +00:00
//------------------------------------------------------------------------------
2004-08-28 16:21:25 +00:00
mrw :: Exec & mrw :: Exec :: operator >> ( std :: string & res ) throw ( std :: exception ) {
2004-04-21 06:39:20 +00:00
execute ();
res += _res ;
return * this ;
}
2005-04-19 18:48:00 +00:00
//------------------------------------------------------------------------------
2004-08-28 16:21:25 +00:00
mrw :: Exec :: operator std :: string & () throw ( std :: exception ) {
2004-04-21 06:39:20 +00:00
if ( ! _success ) execute ();
return _res ;
}
2005-04-19 18:48:00 +00:00
//------------------------------------------------------------------------------
2004-04-21 06:39:20 +00:00
mrw :: Exec :: operator bool () throw ( std :: bad_exception ) {
return _success ;
}
2005-04-19 18:48:00 +00:00
//------------------------------------------------------------------------------
2004-08-28 16:21:25 +00:00
std :: string & mrw :: Exec :: result () throw ( std :: exception ) {
2004-04-21 06:39:20 +00:00
if ( ! _success ) execute ();
return _res ;
}
2005-04-19 18:48:00 +00:00
//------------------------------------------------------------------------------
2004-08-28 16:21:25 +00:00
std :: string & mrw :: Exec :: error () throw ( std :: exception ) {
2004-04-21 06:39:20 +00:00
if ( ! _success ) execute ();
return _err ;
}
2005-04-19 18:48:00 +00:00
//------------------------------------------------------------------------------
2004-04-21 06:39:20 +00:00
bool mrw :: Exec :: success () throw ( std :: bad_exception ) {
return _success ;
}
2005-04-19 18:48:00 +00:00
//================================================================== PartialExec
//------------------------------------------------------------------------------
mrw :: PartialExec :: PartialExec ( const mrw :: Cmd & c ) throw ( std :: bad_exception ) :
Exec ( c ), _finished ( true ), _finish ( false ) {
}
//------------------------------------------------------------------------------
mrw :: PartialExec :: PartialExec ( mrw :: PartialExec & e )
throw ( std :: bad_exception ) :
Exec ( e ), _finished ( e . _finished ), _finish ( e . _finish ),
_stdIn ( e . _stdIn ), _stdOut ( e . _stdOut ), _stdErr ( e . _stdErr ), _input ( e . _input ),
_num0 ( e . _num0 ), _num1 ( e . _num1 ), _num2 ( e . _num2 ),
_lastPid ( e . _lastPid ), _pid ( e . _pid ) {
e . _finished = true ;
}
//------------------------------------------------------------------------------
mrw :: PartialExec :: PartialExec ( const mrw :: PartialExec & e )
throw ( std :: bad_exception ) :
Exec ( e ), _finished ( e . _finished ), _finish ( e . _finish ),
_input ( e . _input ),
_num0 ( e . _num0 ), _num1 ( e . _num1 ), _num2 ( e . _num2 ),
_lastPid ( e . _lastPid ), _pid ( e . _pid ) {
/// @warning @c const is casted away
mrw :: PartialExec & nonConstE ( const_cast < mrw :: PartialExec &> ( e ));
_stdIn = nonConstE . _stdIn ;
_stdOut = nonConstE . _stdOut ;
_stdErr = nonConstE . _stdErr ;
nonConstE . _finished = true ;
nonConstE . _finish = false ;
}
//------------------------------------------------------------------------------
mrw :: PartialExec & mrw :: PartialExec :: operator = ( mrw :: PartialExec & e )
throw ( std :: bad_exception ) {
if ( this ==& e ) return * this ;
* _cmd =* e . _cmd ; _res = e . _res ; _err = e . _err ; _success = e . _success ;
_finished = e . _finished ;
_finish = e . _finish ;
_stdIn = e . _stdIn ; _stdOut = e . _stdOut ; _stdErr = e . _stdErr ;
_input = e . _input ; _num0 = e . _num0 ; _num1 = e . _num1 ; _num2 = e . _num2 ;
_lastPid = e . _lastPid ;
_pid = e . _pid ;
e . _finished = true ;
e . _finish = false ;
return * this ;
}
//------------------------------------------------------------------------------
mrw :: PartialExec & mrw :: PartialExec :: finish () throw () {
_finish = true ;
return * this ;
}
//------------------------------------------------------------------------------
bool mrw :: PartialExec :: finished () throw () {
return _finished ;
}
//------------------------------------------------------------------------------
mrw :: PartialExec & mrw :: PartialExec :: start ( bool useInput )
throw ( std :: exception ) {
if ( ! _finished ) throw mrw :: runtime_error ( "running process not yet finished" );
/** This method calls @c fork, sets up a pipe connection to pass @c
stdin, @c stdout and @c stderr between the child process and the
parent process using mrw::Pipe and calls @c execvp to execute
the program. */
_success = false ;
_finish = ! useInput ;
_input = "" ;
_res = _err = "" ;
_stdIn = std :: auto_ptr < mrw :: Pipe > ( new mrw :: Pipe ( mrw :: Pipe :: block_input ));
_stdOut = std :: auto_ptr < mrw :: Pipe > ( new mrw :: Pipe ( mrw :: Pipe :: block_output ));
_stdErr = std :: auto_ptr < mrw :: Pipe > ( new mrw :: Pipe ( mrw :: Pipe :: block_output ));
if ( !* _stdIn || !* _stdOut || !* _stdErr )
throw mrw :: ExecutionFailedExc ( "cannot create pipe" , * _cmd );
_lastPid = 0 ;
_pid = fork ();
if ( _pid < 0 ) throw ExecutionFailedExc ( "cannot fork" , * _cmd );
if ( _pid ) { // parent
_stdIn -> close_in ();
_stdOut -> close_out ();
_stdErr -> close_out ();
if ( !* _stdIn || !* _stdOut || !* _stdErr )
throw ExecutionFailedExc ( "cannot close pipes" , * _cmd );
_num0 = _num1 = _num2 = 1 ;
_finished = false ;
} else { // child
_stdIn -> close_out ();
_stdOut -> close_in ();
_stdErr -> close_in ();
_stdIn -> connect_cin ();
_stdOut -> connect_cout ();
_stdErr -> connect_cerr ();
execvp ( _cmd -> path (), _cmd -> args ());
exit ( 1 ); // execute failed
}
_success = true ;
return * this ;
}
//------------------------------------------------------------------------------
std :: pair < std :: string , std :: string >
mrw :: PartialExec :: read ( const std :: string & input , bool exc )
throw ( std :: exception ) {
std :: pair < std :: string , std :: string > output ;
/** @note @c input length must be smaller than @c SSIZE_MAX.
I'll only add support for longer strings upon request. */
assert ( input . size () <= SSIZE_MAX &&
"sdin input exeeds C library limit in mrw::Exec "
"please contact the author of the library" );
/** @warning After calling finish(), it is forbidden to pass
any @c input string, it must then always be empty,
because the pipe is already closed! */
assert ( ! ( _finish && input . size ()) &&
"after calling PartialExec::finish(), it is forbidden "
"to pass new input text, because the pipe is already "
"closed! this is a programming but that must be solved!" );
_input += input ;
/* It sometimes did not get the whole input since I changed to non
blocking pipes. Now I have found the solution to the problems:
Non blocking IO does not work in conjunction with select! Also
the pipe must not be nonblocking on both ends, but only on
one. */
if ( ! _finished ) try { // not finished
char buf [ 4096 ];
int s ( 0 );
if ( ! _lastPid && ( _lastPid = waitpid ( _pid , & s , WNOHANG ))) {
if ( _lastPid != _pid || WIFEXITED ( s ) != 0 && WEXITSTATUS ( s ) != 0 )
throw ExecutionFailedExc ( "execution failed" , * _cmd );
}
// check and handle stdin
if ( _input . size () && _num0 !=- 1 &&
( _num0 = write ( _stdIn -> ostream (), _input . c_str (), _input . size ())) > 0 ) {
if (( unsigned int ) _num0 < _input . size ())
_input = _input . substr ( _num0 );
else if (( unsigned int ) _num0 == _input . size ())
_input . clear ();
} else if ( _num0 ==- 1 )
if ( errno != EINTR && errno != EAGAIN )
throw ExecutionFailedExc ( "writing stdin" , * _cmd );
else
_num0 = 1 ;
// check and handle stdout
if ( _num1 && ( _num1 =:: read ( _stdOut -> istream (), buf , sizeof ( buf ))) > 0 )
_res += output . first = std :: string ( buf , _num1 );
else if ( _num1 ==- 1 )
if ( errno != EINTR && errno != EAGAIN )
throw ExecutionFailedExc ( "readin stdout" , * _cmd );
else
_num1 = 1 ;
// check and handle stderr
if ( _num2 && ( _num2 =:: read ( _stdErr -> istream (), buf , sizeof ( buf ))) > 0 )
_err += output . second = std :: string ( buf , _num2 );
else if ( _num2 ==- 1 )
if ( errno != EINTR && errno != EAGAIN )
throw ExecutionFailedExc ( "readin stderr" , * _cmd );
else
_num2 = 1 ;
if ( _finish && ! _input . size ()) {
_stdIn -> close_out ();
_num0 = 0 ;
}
_finished = _finish && ! _input . size () && ! _num1 && ! _num2 && _lastPid ;
} catch ( mrw :: exception & x ) {
_finished = true ;
_success = false ;
if ( exc ) throw ;
return output ;
}
if ( _finished ) _success = true ;
return output ;
}
//------------------------------------------------------------------------------
mrw :: PartialExec & mrw :: PartialExec :: terminate () throw () {
kill ( _pid , SIGTERM );
return * this ;
}