C++ Library containing a lot of needful things: Stack Trace, Command Line Parser, Resource Handling, Configuration Files, Unix Command Execution, Directories, Regular Expressions, Tokenizer, Function Trace, Standard Extensions.
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
164 lines
4.5 KiB
164 lines
4.5 KiB
21 years ago
|
#include <mrw/exec.hpp>
|
||
|
#include <mrw/unistd.hpp>
|
||
|
#include <sys/wait.h> // waitpid
|
||
|
#include <unistd.h> // fork, exec
|
||
|
#include <string.h> // memcpy
|
||
|
|
||
|
#include <iostream>
|
||
|
|
||
|
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
|
||
|
stdot 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;
|
||
|
}
|