Implement controls for file descriptor inheritance
[libs/core.git] / source / core / unix / process.cpp
1 #include <unistd.h>
2 #include <sys/wait.h>
3 #include <signal.h>
4 #include <msp/core/systemerror.h>
5 #include <msp/fs/dir.h>
6 #include <msp/io/console.h>
7 #include "process.h"
8 #include "process_private.h"
9
10 using namespace std;
11
12 namespace Msp {
13
14 Process::~Process()
15 { }
16
17 void Process::platform_get_self_info(Private &priv)
18 {
19         priv.info.pid = getpid();
20 }
21
22 void Process::execute(const string &command, bool path_search, const Arguments &args)
23 {
24         pid_t pid = 0;
25         if(this!=_self)
26                 pid = fork();
27
28         if(pid==-1)
29                 throw system_error("fork");
30         else if(pid==0)
31         {
32                 try
33                 {
34                         vector<const char *> argv(args.size()+2);
35                         argv[0] = command.c_str();
36                         for(unsigned i=0; i<args.size(); ++i)
37                                 argv[i+1] = args[i].c_str();
38                         argv[args.size()+1] = 0;
39
40                         if(redirect)
41                         {
42                                 // dup2 clears O_CLOEXEC
43                                 if(cin)
44                                         IO::cin.redirect(*cin);
45                                 if(cout)
46                                         IO::cout.redirect(*cout);
47                                 if(cerr)
48                                         IO::cerr.redirect(*cerr);
49                         }
50
51                         if(!work_dir.empty())
52                                 FS::chdir(work_dir);
53
54                         if(path_search)
55                                 execvp(command.c_str(), const_cast<char *const *>(&argv[0]));
56                         else
57                                 execv(command.c_str(), const_cast<char *const *>(&argv[0]));
58                 }
59                 catch(...)
60                 { }
61                 _exit(255);
62         }
63         else
64         {
65                 priv->info.pid = pid;
66                 running = true;
67         }
68 }
69
70 bool Process::wait(bool block)
71 {
72         if(!running)
73                 throw logic_error("not running");
74
75         int status;
76         int pid = waitpid(priv->info.pid, &status, (block ? 0 : WNOHANG));
77         if(pid==-1)
78                 throw system_error("waitpid");
79
80         if(pid)
81         {
82                 finished = true;
83                 running = false;
84                 if(WIFEXITED(status))
85                         exit_code = WEXITSTATUS(status);
86                 else if(WIFSIGNALED(status))
87                         exit_code = 0x100|WTERMSIG(status);
88         }
89
90         return finished;
91 }
92
93 void Process::terminate()
94 {
95         ::kill(priv->info.pid, SIGTERM);
96 }
97
98 void Process::kill()
99 {
100         ::kill(priv->info.pid, SIGKILL);
101 }
102
103 void Process::interrupt()
104 {
105         ::kill(priv->info.pid, SIGINT);
106 }
107
108
109 Process::Private::Private()
110 {
111         info.pid = 0;
112 }
113
114 } // namespace Msp