# include <mrw/exec.hpp>
# include <mrw/unistd.hpp>
# include <sys/wait.h> // waitpid
# include <unistd.h> // fork, exec
# include <string.h> // memcpy
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
*/
}
mrw : : Cmd : : Cmd ( const std : : string & c ) throw ( std : : bad_exception ) {
_cmd . push_back ( c ) ;
}
mrw : : Cmd & mrw : : Cmd : : operator , ( const std : : string & arg )
throw ( std : : bad_exception ) {
_cmd . push_back ( arg ) ;
return * this ;
}
mrw : : Cmd & mrw : : Cmd : : operator < < ( const std : : string & arg )
throw ( std : : bad_exception ) {
_cmd . push_back ( arg ) ;
return * this ;
}
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 ;
}
mrw : : Cmd : : operator mrw : : Exec ( ) const throw ( std : : bad_exception ) {
return mrw : : Exec ( * this ) ;
}
mrw : : Exec mrw : : Cmd : : execute ( bool throwExc ) const throw ( mrw : : exception ) {
return mrw : : Exec ( * this ) . execute ( throwExc ) ;
}
const char * mrw : : Cmd : : path ( ) const throw ( std : : bad_exception ) {
return _cmd . front ( ) . c_str ( ) ;
}
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 ;
}
mrw : : Exec : : Exec ( const mrw : : Cmd & c ) throw ( std : : bad_exception ) :
_cmd ( new mrw : : Cmd ( c ) ) , _success ( false ) {
}
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 ) {
}
mrw : : Exec : : ~ Exec ( ) throw ( ) {
delete _cmd ;
}
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 ;
}
mrw : : Exec & mrw : : Exec : : execute ( bool throwExc ) throw ( mrw : : exception ) {
/** This method calls @c fork, sets up a pipe connection to pass @c
stdout and @ c stderr from the child process to the parent process
using mrw : : pipe and calls @ c execvp to execute the program . */
_success = false ;
_res = _err = " " ;
mrw : : pipe stdOut , stdErr ;
if ( ! stdOut | | ! stdErr )
throw mrw : : ExecutionFailedExc ( " cannot create pipe " , * _cmd ) ;
pid_t pid ( fork ( ) ) ;
if ( pid < 0 )
throw ExecutionFailedExc ( " cannot fork " , * _cmd ) ;
if ( pid ) { // parent
stdOut . close_out ( ) ;
stdErr . close_out ( ) ;
if ( ! stdOut | | ! stdErr )
throw ExecutionFailedExc ( " cannot close pipe " , * _cmd ) ;
int num1 ( 0 ) , num2 ( 0 ) ;
for ( char buf1 [ 4096 ] , buf2 [ 4096 ] ;
( num1 = read ( stdOut . istream ( ) , buf1 , sizeof ( buf1 ) ) ) > 0 | |
num1 = = - 1 & & errno = = EINTR | |
( num2 = read ( stdErr . istream ( ) , buf2 , sizeof ( buf2 ) ) ) > 0 | |
num2 = = - 1 & & errno = = EINTR ;
_res + = std : : string ( buf1 , num1 ) , _err + = std : : string ( buf2 , num2 ) ) ;
if ( num1 = = - 1 | | num2 = = - 1 )
throw ExecutionFailedExc ( " cannot_ read pipe " , * _cmd ) ;
// wait for child to get return code
int s ( 0 ) ;
if ( waitpid ( pid , & s , 0 ) ! = pid | | WIFEXITED ( s ) ! = 0 & & WEXITSTATUS ( s ) ! = 0 ) {
if ( throwExc ) {
throw ExecutionFailedExc ( " execution failed " , * _cmd ) ;
} else {
_success = false ;
return * this ;
}
}
} else { // child
stdOut . close_in ( ) ;
stdErr . close_in ( ) ;
stdOut . connect_cout ( ) ;
stdErr . connect_cerr ( ) ;
execvp ( _cmd - > path ( ) , _cmd - > args ( ) ) ;
exit ( 1 ) ; // execute failed
}
_success = true ;
return * this ;
}
mrw : : Exec & mrw : : Exec : : operator > > ( std : : string & res ) throw ( mrw : : exception ) {
execute ( ) ;
res + = _res ;
return * this ;
}
mrw : : Exec : : operator std : : string & ( ) throw ( mrw : : exception ) {
if ( ! _success ) execute ( ) ;
return _res ;
}
mrw : : Exec : : operator bool ( ) throw ( std : : bad_exception ) {
return _success ;
}
std : : string & mrw : : Exec : : result ( ) throw ( mrw : : exception ) {
if ( ! _success ) execute ( ) ;
return _res ;
}
std : : string & mrw : : Exec : : error ( ) throw ( mrw : : exception ) {
if ( ! _success ) execute ( ) ;
return _err ;
}
bool mrw : : Exec : : success ( ) throw ( std : : bad_exception ) {
return _success ;
}