4 #include <msp/fs/dir.h>
5 #include <msp/io/console.h>
6 #include <msp/io/file.h>
7 #include <msp/io/print.h>
8 #include <msp/time/units.h>
9 #include "externaltask.h"
14 ExternalTask::ExternalTask(const vector<string> &a, const FS::Path &wd):
19 stdout_dest(PASSTHROUGH),
20 stderr_dest(PASSTHROUGH),
24 ExternalTask::~ExternalTask()
29 string ExternalTask::get_command() const
32 for(vector<string>::const_iterator i=argv.begin(); i!=argv.end(); ++i)
37 for(string::const_iterator j=i->begin(); j!=i->end(); ++j)
39 if(*j=='"' || *j=='\'' || *j==' ' || *j=='\\' || *j=='&')
48 void ExternalTask::start()
50 if(stdout_dest==CAPTURE || stderr_dest==CAPTURE)
51 capture_pipe = new IO::Pipe;
64 vector<const char *> cargv(argv.size()+1);
65 for(unsigned i=0; i<argv.size(); ++i)
66 cargv[i] = argv[i].c_str();
69 if(stdout_dest==IGNORE || stderr_dest==IGNORE)
71 IO::File devnull("/dev/null", IO::M_WRITE);
72 if(stdout_dest==IGNORE)
73 IO::cout.redirect(devnull);
74 if(stderr_dest==IGNORE)
75 IO::cerr.redirect(devnull);
80 if(stdout_dest==CAPTURE)
81 IO::cout.redirect(*capture_pipe);
82 if(stderr_dest==CAPTURE)
83 IO::cerr.redirect(*capture_pipe);
89 execvp(cargv.front(), const_cast<char *const *>(&cargv.front()));
90 IO::print("Couldn't execute %s\n", argv.front());
95 Task::Status ExternalTask::check()
97 return do_wait(false);
100 Task::Status ExternalTask::wait()
102 return do_wait(true);
105 Task::Status ExternalTask::do_wait(bool block)
110 if(waitpid(pid, &status, (block ? 0 : WNOHANG))==pid)
112 if(WIFEXITED(status))
113 exit_code = WEXITSTATUS(status);
114 else if(WIFSIGNALED(status))
115 exit_code = 256+WTERMSIG(status);
121 // Do this after waiting to avoid a race condition
124 while(IO::poll(*capture_pipe, IO::P_INPUT, Time::zero))
127 unsigned len = capture_pipe->read(buf, sizeof(buf));
128 output.append(buf, len);
137 signal_finished.emit(!exit_code);
140 return exit_code ? ERROR : SUCCESS;
143 void ExternalTask::set_stdout(Destination d)
148 void ExternalTask::set_stderr(Destination d)
153 string ExternalTask::run_and_capture_output(const Arguments &argv, const FS::Path &wd)
155 ExternalTask task(argv, wd);
156 task.set_stdout(CAPTURE);
157 task.set_stderr(IGNORE);
159 if(task.wait()!=SUCCESS)
160 throw runtime_error(format("%s failed", argv.front()));
161 return task.get_output();