2004-04-21 06:39:20 +00:00
|
|
|
#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
|
|
|
|
*/
|
|
|
|
//@{
|
|
|
|
|
|
|
|
class Cmd;
|
|
|
|
|
|
|
|
/** @brief Exception: Execution of command failed.
|
2004-04-23 16:03:29 +00:00
|
|
|
@pre #include <mrw/exec.hpp>
|
2004-04-21 06:39:20 +00:00
|
|
|
|
|
|
|
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.
|
2004-04-23 16:03:29 +00:00
|
|
|
@pre #include <mrw/exec.hpp>
|
2004-04-21 06:39:20 +00:00
|
|
|
|
|
|
|
This class handles the execution of a command in a new process
|
2004-04-23 16:03:29 +00:00
|
|
|
and returns the two streams @c cout and @c cerr, also known as @c
|
|
|
|
stderr and @c stdout.
|
2004-04-21 06:39:20 +00:00
|
|
|
|
|
|
|
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 bool
|
|
|
|
- @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=true) throw(mrw::exception);
|
|
|
|
|
|
|
|
/** @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(mrw::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(mrw::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(mrw::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(mrw::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
|
2004-04-23 16:03:29 +00:00
|
|
|
@pre #include <mrw/exec.hpp>
|
2004-04-21 06:39:20 +00:00
|
|
|
|
|
|
|
This class is used in conjunction with mrw::Exec. It mus 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 std::string the name of the program to execute (no parameter)
|
|
|
|
@note There is no default constructor. */
|
|
|
|
Cmd(const std::string&) throw(std::bad_exception);
|
|
|
|
|
|
|
|
/** @brief Append a parameter to a command
|
|
|
|
@param std::string a parameter / commandline argument
|
|
|
|
to append to the command */
|
|
|
|
Cmd& operator,(const std::string&) throw(std::bad_exception);
|
|
|
|
|
|
|
|
/** @brief Append a parameter to a command
|
|
|
|
@param std::string a parameter / commandline argument
|
|
|
|
to append to the command */
|
|
|
|
Cmd& operator<<(const std::string&) 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 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 bool
|
|
|
|
- @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=true) const throw(mrw::exception);
|
|
|
|
|
|
|
|
private:
|
|
|
|
friend class Exec; // is allowed to call path() and args()
|
|
|
|
Cmd(); // no default constructor
|
|
|
|
const char* path() const throw(std::bad_exception);
|
|
|
|
char** args() const throw(std::bad_exception);
|
|
|
|
typedef std::list<std::string> ArgList;
|
|
|
|
ArgList _cmd;
|
|
|
|
};
|
|
|
|
//@}
|
|
|
|
}
|
|
|
|
#endif
|