408 lines
14 KiB
C++
408 lines
14 KiB
C++
/** @file
|
|
|
|
$Id$
|
|
|
|
$Date$
|
|
$Author$
|
|
|
|
@copy © Marc Wä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 / 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 / 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
|