Revert #910.
[platform/upstream/ninja.git] / src / subprocess-posix.cc
1 // Copyright 2012 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "subprocess.h"
16
17 #include <assert.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <poll.h>
21 #include <unistd.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <sys/wait.h>
25
26 #include "util.h"
27
28 Subprocess::Subprocess(bool use_console) : fd_(-1), pid_(-1),
29                                            use_console_(use_console) {
30 }
31
32 Subprocess::~Subprocess() {
33   if (fd_ >= 0)
34     close(fd_);
35   // Reap child if forgotten.
36   if (pid_ != -1)
37     Finish();
38 }
39
40 bool Subprocess::Start(SubprocessSet* set, const string& command) {
41   int output_pipe[2];
42   if (pipe(output_pipe) < 0)
43     Fatal("pipe: %s", strerror(errno));
44   fd_ = output_pipe[0];
45 #if !defined(USE_PPOLL)
46   // If available, we use ppoll in DoWork(); otherwise we use pselect
47   // and so must avoid overly-large FDs.
48   if (fd_ >= static_cast<int>(FD_SETSIZE))
49     Fatal("pipe: %s", strerror(EMFILE));
50 #endif  // !USE_PPOLL
51   SetCloseOnExec(fd_);
52
53   pid_ = fork();
54   if (pid_ < 0)
55     Fatal("fork: %s", strerror(errno));
56
57   if (pid_ == 0) {
58     close(output_pipe[0]);
59
60     // Track which fd we use to report errors on.
61     int error_pipe = output_pipe[1];
62     do {
63       if (sigaction(SIGINT, &set->old_int_act_, 0) < 0)
64         break;
65       if (sigaction(SIGTERM, &set->old_term_act_, 0) < 0)
66         break;
67       if (sigaction(SIGHUP, &set->old_hup_act_, 0) < 0)
68         break;
69       if (sigprocmask(SIG_SETMASK, &set->old_mask_, 0) < 0)
70         break;
71
72       if (!use_console_) {
73         // Put the child in its own process group, so ctrl-c won't reach it.
74         if (setpgid(0, 0) < 0)
75           break;
76
77         // Open /dev/null over stdin.
78         int devnull = open("/dev/null", O_RDONLY);
79         if (devnull < 0)
80           break;
81         if (dup2(devnull, 0) < 0)
82           break;
83         close(devnull);
84
85         if (dup2(output_pipe[1], 1) < 0 ||
86             dup2(output_pipe[1], 2) < 0)
87           break;
88
89         // Now can use stderr for errors.
90         error_pipe = 2;
91         close(output_pipe[1]);
92       }
93       // In the console case, output_pipe is still inherited by the child and
94       // closed when the subprocess finishes, which then notifies ninja.
95
96       execl("/bin/sh", "/bin/sh", "-c", command.c_str(), (char *) NULL);
97     } while (false);
98
99     // If we get here, something went wrong; the execl should have
100     // replaced us.
101     char* err = strerror(errno);
102     if (write(error_pipe, err, strlen(err)) < 0) {
103       // If the write fails, there's nothing we can do.
104       // But this block seems necessary to silence the warning.
105     }
106     _exit(1);
107   }
108
109   close(output_pipe[1]);
110   return true;
111 }
112
113 void Subprocess::OnPipeReady() {
114   char buf[4 << 10];
115   ssize_t len = read(fd_, buf, sizeof(buf));
116   if (len > 0) {
117     buf_.append(buf, len);
118   } else {
119     if (len < 0)
120       Fatal("read: %s", strerror(errno));
121     close(fd_);
122     fd_ = -1;
123   }
124 }
125
126 ExitStatus Subprocess::Finish() {
127   assert(pid_ != -1);
128   int status;
129   if (waitpid(pid_, &status, 0) < 0)
130     Fatal("waitpid(%d): %s", pid_, strerror(errno));
131   pid_ = -1;
132
133   if (WIFEXITED(status)) {
134     int exit = WEXITSTATUS(status);
135     if (exit == 0)
136       return ExitSuccess;
137   } else if (WIFSIGNALED(status)) {
138     if (WTERMSIG(status) == SIGINT || WTERMSIG(status) == SIGTERM
139         || WTERMSIG(status) == SIGHUP)
140       return ExitInterrupted;
141   }
142   return ExitFailure;
143 }
144
145 bool Subprocess::Done() const {
146   return fd_ == -1;
147 }
148
149 const string& Subprocess::GetOutput() const {
150   return buf_;
151 }
152
153 int SubprocessSet::interrupted_;
154
155 void SubprocessSet::SetInterruptedFlag(int signum) {
156   interrupted_ = signum;
157 }
158
159 void SubprocessSet::HandlePendingInterruption() {
160   sigset_t pending;
161   sigemptyset(&pending);
162   if (sigpending(&pending) == -1) {
163     perror("ninja: sigpending");
164     return;
165   }
166   if (sigismember(&pending, SIGINT))
167     interrupted_ = SIGINT;
168   else if (sigismember(&pending, SIGTERM))
169     interrupted_ = SIGTERM;
170   else if (sigismember(&pending, SIGHUP))
171     interrupted_ = SIGHUP;
172 }
173
174 SubprocessSet::SubprocessSet() {
175   sigset_t set;
176   sigemptyset(&set);
177   sigaddset(&set, SIGINT);
178   sigaddset(&set, SIGTERM);
179   sigaddset(&set, SIGHUP);
180   if (sigprocmask(SIG_BLOCK, &set, &old_mask_) < 0)
181     Fatal("sigprocmask: %s", strerror(errno));
182
183   struct sigaction act;
184   memset(&act, 0, sizeof(act));
185   act.sa_handler = SetInterruptedFlag;
186   if (sigaction(SIGINT, &act, &old_int_act_) < 0)
187     Fatal("sigaction: %s", strerror(errno));
188   if (sigaction(SIGTERM, &act, &old_term_act_) < 0)
189     Fatal("sigaction: %s", strerror(errno));
190   if (sigaction(SIGHUP, &act, &old_hup_act_) < 0)
191     Fatal("sigaction: %s", strerror(errno));
192 }
193
194 SubprocessSet::~SubprocessSet() {
195   Clear();
196
197   if (sigaction(SIGINT, &old_int_act_, 0) < 0)
198     Fatal("sigaction: %s", strerror(errno));
199   if (sigaction(SIGTERM, &old_term_act_, 0) < 0)
200     Fatal("sigaction: %s", strerror(errno));
201   if (sigaction(SIGHUP, &old_hup_act_, 0) < 0)
202     Fatal("sigaction: %s", strerror(errno));
203   if (sigprocmask(SIG_SETMASK, &old_mask_, 0) < 0)
204     Fatal("sigprocmask: %s", strerror(errno));
205 }
206
207 Subprocess *SubprocessSet::Add(const string& command, bool use_console) {
208   Subprocess *subprocess = new Subprocess(use_console);
209   if (!subprocess->Start(this, command)) {
210     delete subprocess;
211     return 0;
212   }
213   running_.push_back(subprocess);
214   return subprocess;
215 }
216
217 #ifdef USE_PPOLL
218 bool SubprocessSet::DoWork() {
219   vector<pollfd> fds;
220   nfds_t nfds = 0;
221
222   for (vector<Subprocess*>::iterator i = running_.begin();
223        i != running_.end(); ++i) {
224     int fd = (*i)->fd_;
225     if (fd < 0)
226       continue;
227     pollfd pfd = { fd, POLLIN | POLLPRI, 0 };
228     fds.push_back(pfd);
229     ++nfds;
230   }
231
232   interrupted_ = 0;
233   int ret = ppoll(&fds.front(), nfds, NULL, &old_mask_);
234   if (ret == -1) {
235     if (errno != EINTR) {
236       perror("ninja: ppoll");
237       return false;
238     }
239     return IsInterrupted();
240   }
241
242   HandlePendingInterruption();
243   if (IsInterrupted())
244     return true;
245
246   nfds_t cur_nfd = 0;
247   for (vector<Subprocess*>::iterator i = running_.begin();
248        i != running_.end(); ) {
249     int fd = (*i)->fd_;
250     if (fd < 0)
251       continue;
252     assert(fd == fds[cur_nfd].fd);
253     if (fds[cur_nfd++].revents) {
254       (*i)->OnPipeReady();
255       if ((*i)->Done()) {
256         finished_.push(*i);
257         i = running_.erase(i);
258         continue;
259       }
260     }
261     ++i;
262   }
263
264   return IsInterrupted();
265 }
266
267 #else  // !defined(USE_PPOLL)
268 bool SubprocessSet::DoWork() {
269   fd_set set;
270   int nfds = 0;
271   FD_ZERO(&set);
272
273   for (vector<Subprocess*>::iterator i = running_.begin();
274        i != running_.end(); ++i) {
275     int fd = (*i)->fd_;
276     if (fd >= 0) {
277       FD_SET(fd, &set);
278       if (nfds < fd+1)
279         nfds = fd+1;
280     }
281   }
282
283   interrupted_ = 0;
284   int ret = pselect(nfds, &set, 0, 0, 0, &old_mask_);
285   if (ret == -1) {
286     if (errno != EINTR) {
287       perror("ninja: pselect");
288       return false;
289     }
290     return IsInterrupted();
291   }
292
293   HandlePendingInterruption();
294   if (IsInterrupted())
295     return true;
296
297   for (vector<Subprocess*>::iterator i = running_.begin();
298        i != running_.end(); ) {
299     int fd = (*i)->fd_;
300     if (fd >= 0 && FD_ISSET(fd, &set)) {
301       (*i)->OnPipeReady();
302       if ((*i)->Done()) {
303         finished_.push(*i);
304         i = running_.erase(i);
305         continue;
306       }
307     }
308     ++i;
309   }
310
311   return IsInterrupted();
312 }
313 #endif  // !defined(USE_PPOLL)
314
315 Subprocess* SubprocessSet::NextFinished() {
316   if (finished_.empty())
317     return NULL;
318   Subprocess* subproc = finished_.front();
319   finished_.pop();
320   return subproc;
321 }
322
323 void SubprocessSet::Clear() {
324   for (vector<Subprocess*>::iterator i = running_.begin();
325        i != running_.end(); ++i)
326     // Since the foreground process is in our process group, it will receive
327     // the interruption signal (i.e. SIGINT or SIGTERM) at the same time as us.
328     if (!(*i)->use_console_)
329       kill(-(*i)->pid_, interrupted_);
330   for (vector<Subprocess*>::iterator i = running_.begin();
331        i != running_.end(); ++i)
332     delete *i;
333   running_.clear();
334 }