/** @file
$ Id $
$ Date $
$ Author $
@ copy & copy ; Marc W & auml ; ckerlin
@ license LGPL , see file < a href = " license.html " > COPYING < / a >
$ Log $
Revision 1.5 2004 / 12 / 14 20 : 30 : 09 marc
added possibility to pass string to stdin of child process
Revision 1.4 2004 / 10 / 07 09 : 27 : 01 marc
errors in documentation
Revision 1.3 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
*/
# ifndef __MRW_EXEC_HPP__
# define __MRW_EXEC_HPP__
# include <string>
# include <list>
# include <mrw/exception.hpp>
namespace mrw {
/** @defgroup CmdExec Execute UNIX Commands
There is no easy way to safely execute UNIX commands and to
return the output of the callee to the caller . @ c system ist
first of all known to be unsafe , because it opens a shell , and
second there is no way to transfer the output back to the
caller . On the other hand , starting a new process with @ c fork
and @ c exec and passing the output of the callee to the caller
using pipes is quite complex and needs much more than one simple
line of code . This is the gap that is filled with this command
execution classes . There ' s a class for the command to be
executed and a class for the execution of the command .
Forking a subprocess and evaluating the result becomes so easy :
@ code
try {
// execute the command: /bin/ls -l /tmp
mrw : : Exec ls =
( mrw : : Cmd ( " /bin/ls " ) , " -l " , " /tmp " ) . execute ( false ) ;
// evaluate the result
if ( ls . success ( ) )
std : : cout < < " Execution successful, result was: " < < std : : endl ;
else
std : : cerr < < " Error in execution, error was: " < < std : : endl ;
std : : cout < < ls . result ( ) < < std : : endl ;
std : : cerr < < ls . error ( ) < < std : : endl ;
} catch ( ExecutionFailedExc & x ) {
// a fatal execution error occurred
// you can trace x.what() and x.stacktrace()
}
@ endcode
It is also possible to pass an @ c stdin input argument to the
subprocess called :
@ code
try {
mrw : : Exec cat = mrw : : Cmd ( " /bin/cat " )
. execute ( " this is passed to stdin " ) ;
// "cat" passes all from stdin to stdout, therefore:
assert ( cat . result ( ) = = " this is passed to stdin " ) ;
} catch ( . . . ) { } // ignore
@ endcode
*/
//@{
class Cmd ;
/** @brief Exception: Execution of command failed.
@ pre # include < mrw / exec . hpp >
This exception is thrown , if the exection of a command in
mrw : : Exec is failed . That means , it was not possible to fork or
to create the necessary pipes , or the command executing process
terminated with an error . In the last case , you can access the
error stream from @ c stderr respectively @ c cerr with method
mrw : : Exec : : error ( ) .
*/
class ExecutionFailedExc : public mrw : : exception {
public :
ExecutionFailedExc ( const std : : string & , const std : : string & )
throw ( std : : bad_exception ) ;
virtual ~ ExecutionFailedExc ( ) throw ( ) { }
virtual const char * what ( ) const throw ( ) { return _what . c_str ( ) ; }
private :
std : : string _what ;
} ;
/** @brief Execute a command in a new process.
@ pre # include < mrw / exec . hpp >
This class handles the execution of a command in a new process
and returns the two streams @ c cout and @ c cerr , also known as @ c
stderr and @ c stdout .
Method @ c execute can optionally also take a string parameter
that is passed to @ c stdin of the child process .
There are different ways of usage for this class . A simple way ,
one line of code , to get only the resulting stream ( no error )
is :
@ code
string stdout =
( mrw : : Cmd ( " /bin/ls " ) , " -l " , " /tmp " ) . execute ( false ) . result ( ) ;
@ endcode
If you need not only the resulting @ c stdout stream , but also
the error stream @ c stderr , then you need to store the result :
@ code
mrw : : Exec ls =
( mrw : : Cmd ( " /bin/ls " ) , " -l " , " /tmp " ) . execute ( false ) ;
if ( ! ls ) . . . ; // command termianted with error
// ls.result() contains stdout
// ls.error() contains stderr
@ endcode
@ note Please note that the command execution may throw an exception .
*/
class Exec {
public :
/** @brief Create an executor given a command.
Construction without passing a command is not possible . */
Exec ( const mrw : : Cmd & ) throw ( std : : bad_exception ) ;
Exec ( const mrw : : Exec & ) throw ( std : : bad_exception ) ;
~ Exec ( ) throw ( ) ;
Exec & operator = ( const mrw : : Exec & ) throw ( std : : bad_exception ) ;
/** @brief Execute the command.
@ param exc
- @ c true throw an exception if return status is not zero
- @ c false throw only an exception in case of a fatal error
@ throw ExecutionFailedExc is thrown if
- fork fails
- creation or setup of pipes failed
- if given parameter is @ c true ( the default ) also if the
executed program terminates with an error
*/
Exec & execute ( bool exc = true ) throw ( std : : exception ) ;
/** @brief Execute the command, pass @c stdin.
@ param input Input that is passed to @ c stdin of the child process .
@ param exc
- @ c true throw an exception if return status is not zero
- @ c false throw only an exception in case of a fatal error
@ throw ExecutionFailedExc is thrown if
- fork fails
- creation or setup of pipes failed
- if given parameter is @ c true ( the default ) also if the
executed program terminates with an error
*/
Exec & execute ( const std : : string & input , bool exc = true )
throw ( std : : exception ) ;
/** @brief Execute the command, pass @c stdin.
@ param input Input that is passed to @ c stdin of the child process .
@ param exc
- @ c true throw an exception if return status is not zero
- @ c false throw only an exception in case of a fatal error
@ throw ExecutionFailedExc is thrown if
- fork fails
- creation or setup of pipes failed
- if given parameter is @ c true ( the default ) also if the
executed program terminates with an error
*/
Exec & execute ( char const * const input , bool exc = true )
throw ( std : : exception ) {
return execute ( std : : string ( input ) , exc ) ;
}
/** @brief Executes the command if not done, streams @c stdout into a string
If the command has not yet been executed successfully , it is
first executed , then the @ c stdout output of the called
program is appended to the string .
@ throw ExecutionFailedExc in case of any failure or if the
executed program does not return a zero exit status .
*/
Exec & operator > > ( std : : string & ) throw ( std : : exception ) ;
/** @brief Executes the command if not done, returns @c stdout as string
If the command has not yet been executed successfully , it is
first executed , then the @ c stdout output of the called
program is returned .
@ return @ c stdout of the called program
@ throw ExecutionFailedExc in case of any failure or if the
executed program does not return a zero exit status .
*/
operator std : : string & ( ) throw ( std : : exception ) ;
/** @return
- @ c true if the last execution was successful
- @ c false if the last execution failed or the command was
never executed
*/
operator bool ( ) throw ( std : : bad_exception ) ;
/** @brief Executes the command if not done, returns @c stdout as string
If the command has not yet been executed successfully , it is
first executed , then the @ c stdout output of the called
program is returned .
@ return @ c stdout of the called program
@ throw ExecutionFailedExc in case of any failure or if the
executed program does not return a zero exit status .
*/
std : : string & result ( ) throw ( std : : exception ) ;
/** @brief Executes the command if not done, returns @c stderr as string
If the command has not yet been executed successfully , it is
first executed , then the @ c stderr error output of the called
program is returned .
@ return @ c stderr of the called program
@ throw ExecutionFailedExc in case of any failure or if the
executed program does not return a zero exit status .
*/
std : : string & error ( ) throw ( std : : exception ) ;
/** @return
- @ c true if the last execution was successful
- @ c false if the last execution failed or the command was
never executed
*/
bool success ( ) throw ( std : : bad_exception ) ;
private :
Exec ( ) ; // no default constructor
mrw : : Cmd * _cmd ;
std : : string _res , _err ;
bool _success ;
} ;
/** @brief A system command to be executed
@ pre # include < mrw / exec . hpp >
This class is used in conjunction with mrw : : Exec . It must be
initialized with the command name , then the command parameters
are appended either with commas , or by streaming them into the
command , whatever you like .
You can stream the data into the class :
@ code
mrw : : Cmd ls ( " /bin/ls " ) ; // the command to execute is: /bin/ls
ls < < " -l " < < " /tmp " ; // the command is now: /bin/ls -l /tmp
@ endcode
Or you can setup your command with commas :
@ code
mrw : : Cmd ls = ( mrw : : Cmd ( / bin / ls ) , " -l " , " /tmp " ) ;
@ endcode
*/
class Cmd {
public :
/** @brief Create a command given the name of the executable
@ param command the name of the program to execute ( no parameter )
@ note There is no default constructor . */
Cmd ( const std : : string & command ) throw ( std : : bad_exception ) ;
/** @brief Append a parameter to a command
@ param param a parameter & nbsp ; / commandline argument
to append to the command */
Cmd & operator , ( const std : : string & param ) throw ( std : : bad_exception ) ;
/** @brief Append a parameter to a command
@ param param a parameter & nbsp ; / commandline argument
to append to the command */
Cmd & operator < < ( const std : : string & param ) throw ( std : : bad_exception ) ;
/** @return the command including parameter */
operator std : : string ( ) const throw ( std : : bad_exception ) ;
/** @return a mrw::Exec that's constructed with this class */
operator mrw : : Exec ( ) const throw ( std : : bad_exception ) ;
/** @brief Create a mrw::Exec and execute the command
Creates a mrw : : Exec , executes the command , passes the flag to
mrw : : Exec : : execute ( ) and returns the created mrw : : Exec . The
result of the execution can be retrieved through the returned
mrw : : Exec object : The methods mrw : : Exec : : success ( ) ,
mrw : : Exec : : result ( ) and mrw : : Exec : : error ( ) provide the
necessary information .
@ param exc
- @ c true throw an exception if return status is not zero
- @ c false throw only an exception in case of a fatal error
@ return the mrw : : Exec that has executed the command
@ throw ExecutionFailedExc is thrown if
- fork fails
- creation or setup of pipes failed
- if given parameter is @ c true ( the default ) also if the
executed program terminates with an error
*/
Exec execute ( bool exc = true ) const throw ( std : : exception ) ;
/** @brief Create a mrw::Exec and execute the command given an input
Creates a mrw : : Exec , executes the command , passes the input
and the flag to mrw : : Exec : : execute ( ) and returns the created
mrw : : Exec . The result of the execution can be retrieved
through the returned mrw : : Exec object : The methods
mrw : : Exec : : success ( ) , mrw : : Exec : : result ( ) and
mrw : : Exec : : error ( ) provide the necessary information .
@ param input Input that is passed to @ c stdin of the child process .
@ param exc
- @ c true throw an exception if return status is not zero
- @ c false throw only an exception in case of a fatal error
@ return the mrw : : Exec that has executed the command
@ throw ExecutionFailedExc is thrown if
- fork fails
- creation or setup of pipes failed
- if given parameter is @ c true ( the default ) also if the
executed program terminates with an error
*/
Exec execute ( const std : : string & input , bool exc = true ) const
throw ( std : : exception ) ;
/** @brief Create a mrw::Exec and execute the command given an input
Creates a mrw : : Exec , executes the command , passes the input
and the flag to mrw : : Exec : : execute ( ) and returns the created
mrw : : Exec . The result of the execution can be retrieved
through the returned mrw : : Exec object : The methods
mrw : : Exec : : success ( ) , mrw : : Exec : : result ( ) and
mrw : : Exec : : error ( ) provide the necessary information .
@ param input Input that is passed to @ c stdin of the child process .
@ param exc
- @ c true throw an exception if return status is not zero
- @ c false throw only an exception in case of a fatal error
@ return the mrw : : Exec that has executed the command
@ throw ExecutionFailedExc is thrown if
- fork fails
- creation or setup of pipes failed
- if given parameter is @ c true ( the default ) also if the
executed program terminates with an error
*/
Exec execute ( char const * const input , bool exc = true ) const
throw ( std : : exception ) {
return execute ( std : : string ( input ) , exc ) ;
}
private :
/// Exec is allowed to call @c path() and @c args().
friend class Exec ;
/// No default constructor.
Cmd ( ) ;
const char * path ( ) const throw ( std : : bad_exception ) ;
char * * args ( ) const throw ( std : : bad_exception ) ;
typedef std : : list < std : : string > ArgList ;
ArgList _cmd ;
} ;
//@}
}
# endif