/** @file
$Id$
$Date$
$Author$
@copy © Marc Wäckerlin
@license LGPL, see file COPYING
$Log$
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
- 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
*/
#include
#include
#include
#include // waitpid
#include // fork, exec
#include // 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(std::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(std::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(std::exception) {
execute();
res += _res;
return *this;
}
mrw::Exec::operator std::string&() throw(std::exception) {
if (!_success) execute();
return _res;
}
mrw::Exec::operator bool() throw(std::bad_exception) {
return _success;
}
std::string& mrw::Exec::result() throw(std::exception) {
if (!_success) execute();
return _res;
}
std::string& mrw::Exec::error() throw(std::exception) {
if (!_success) execute();
return _err;
}
bool mrw::Exec::success() throw(std::bad_exception) {
return _success;
}