#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(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 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(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; }