]> git.tdb.fi Git - builder.git/blob - source/externaltask.cpp
Use a unique exit_code value to indicate fork failure
[builder.git] / source / externaltask.cpp
1 #include <cstdlib>
2 #include <unistd.h>
3 #include <sys/wait.h>
4 #include <msp/fs/dir.h>
5 #include <msp/io/print.h>
6 #include "externaltask.h"
7
8 using namespace std;
9 using namespace Msp;
10
11 ExternalTask::ExternalTask(const vector<string> &a, const FS::Path &wd):
12         argv(a),
13         work_dir(wd),
14         pid(-1),
15         exit_code(-1)
16 { }
17
18 string ExternalTask::get_command() const
19 {
20         string cmd;
21         for(vector<string>::const_iterator i=argv.begin(); i!=argv.end(); ++i)
22         {
23                 if(i!=argv.begin())
24                         cmd += ' ';
25
26                 for(string::const_iterator j=i->begin(); j!=i->end(); ++j)
27                 {
28                         if(*j=='"' || *j=='\'' || *j==' ' || *j=='\\' || *j=='&')
29                                 cmd += '\\';
30                         cmd += *j;
31                 }
32         }
33
34         return cmd;
35 }
36
37 void ExternalTask::start()
38 {
39         if((pid = fork()))
40         {
41                 if(pid==-1)
42                         exit_code = 1026;
43                 else
44                         exit_code = 0;
45         }
46         else
47         {
48                 vector<const char *> cargv(argv.size()+1);
49                 for(unsigned i=0; i<argv.size(); ++i)
50                         cargv[i] = argv[i].c_str();
51                 cargv.back() = 0;
52
53                 if(!work_dir.empty())
54                         FS::chdir(work_dir);
55                 execvp(cargv.front(), const_cast<char *const *>(&cargv.front()));
56                 IO::print("Couldn't execute %s\n", argv.front());
57                 exit(1);
58         }
59 }
60
61 Task::Status ExternalTask::check()
62 {
63         if(pid>0)
64         {
65                 int status;
66                 if(waitpid(pid, &status, WNOHANG)==pid)
67                 {
68                         if(WIFEXITED(status))
69                                 exit_code = WEXITSTATUS(status);
70                         else if(WIFSIGNALED(status))
71                                 exit_code = 256+WTERMSIG(status);
72                         else
73                                 exit_code = 1025;
74                         pid = 0;
75
76                         signal_finished.emit(!exit_code);
77                 }
78                 else
79                         return RUNNING;
80         }
81
82         return exit_code ? ERROR : SUCCESS;
83 }