process: Fix races on fatal signal handling in process_start().
[sliver-openvswitch.git] / lib / process.c
1 /*
2  * Copyright (c) 2008, 2009 Nicira Networks.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <config.h>
18 #include "process.h"
19 #include <assert.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <signal.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/stat.h>
26 #include <sys/wait.h>
27 #include <unistd.h>
28 #include "coverage.h"
29 #include "dynamic-string.h"
30 #include "fatal-signal.h"
31 #include "list.h"
32 #include "poll-loop.h"
33 #include "socket-util.h"
34 #include "util.h"
35
36 #define THIS_MODULE VLM_process
37 #include "vlog.h"
38
39 struct process {
40     struct list node;
41     char *name;
42     pid_t pid;
43
44     /* Modified by signal handler. */
45     volatile bool exited;
46     volatile int status;
47 };
48
49 /* Pipe used to signal child termination. */
50 static int fds[2];
51
52 /* All processes. */
53 static struct list all_processes = LIST_INITIALIZER(&all_processes);
54
55 static bool sigchld_is_blocked(void);
56 static void block_sigchld(sigset_t *);
57 static void unblock_sigchld(const sigset_t *);
58 static void sigchld_handler(int signr UNUSED);
59 static bool is_member(int x, const int *array, size_t);
60
61 /* Initializes the process subsystem (if it is not already initialized).  Calls
62  * exit() if initialization fails.
63  *
64  * Calling this function is optional; it will be called automatically by
65  * process_start() if necessary.  Calling it explicitly allows the client to
66  * prevent the process from exiting at an unexpected time. */
67 void
68 process_init(void)
69 {
70     static bool inited;
71     struct sigaction sa;
72
73     if (inited) {
74         return;
75     }
76     inited = true;
77
78     /* Create notification pipe. */
79     if (pipe(fds)) {
80         ovs_fatal(errno, "could not create pipe");
81     }
82     set_nonblocking(fds[0]);
83     set_nonblocking(fds[1]);
84
85     /* Set up child termination signal handler. */
86     memset(&sa, 0, sizeof sa);
87     sa.sa_handler = sigchld_handler;
88     sigemptyset(&sa.sa_mask);
89     sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
90     if (sigaction(SIGCHLD, &sa, NULL)) {
91         ovs_fatal(errno, "sigaction(SIGCHLD) failed");
92     }
93 }
94
95 char *
96 process_escape_args(char **argv)
97 {
98     struct ds ds = DS_EMPTY_INITIALIZER;
99     char **argp;
100     for (argp = argv; *argp; argp++) {
101         const char *arg = *argp;
102         const char *p;
103         if (argp != argv) {
104             ds_put_char(&ds, ' ');
105         }
106         if (arg[strcspn(arg, " \t\r\n\v\\")]) {
107             ds_put_char(&ds, '"');
108             for (p = arg; *p; p++) {
109                 if (*p == '\\' || *p == '\"') {
110                     ds_put_char(&ds, '\\');
111                 }
112                 ds_put_char(&ds, *p);
113             }
114             ds_put_char(&ds, '"');
115         } else {
116             ds_put_cstr(&ds, arg);
117         }
118     }
119     return ds_cstr(&ds);
120 }
121
122 /* Starts a subprocess with the arguments in the null-terminated argv[] array.
123  * argv[0] is used as the name of the process.  Searches the PATH environment
124  * variable to find the program to execute.
125  *
126  * All file descriptors are closed before executing the subprocess, except for
127  * fds 0, 1, and 2 and the 'n_keep_fds' fds listed in 'keep_fds'.  Also, any of
128  * the 'n_null_fds' fds listed in 'null_fds' are replaced by /dev/null.
129  *
130  * Returns 0 if successful, otherwise a positive errno value indicating the
131  * error.  If successful, '*pp' is assigned a new struct process that may be
132  * used to query the process's status.  On failure, '*pp' is set to NULL. */
133 int
134 process_start(char **argv,
135               const int keep_fds[], size_t n_keep_fds,
136               const int null_fds[], size_t n_null_fds,
137               struct process **pp)
138 {
139     sigset_t oldsigs;
140     char *binary;
141     pid_t pid;
142
143     *pp = NULL;
144     process_init();
145     COVERAGE_INC(process_start);
146
147     if (VLOG_IS_DBG_ENABLED()) {
148         char *args = process_escape_args(argv);
149         VLOG_DBG("starting subprocess: %s", args);
150         free(args);
151     }
152
153     /* execvp() will search PATH too, but the error in that case is more
154      * obscure, since it is only reported post-fork. */
155     binary = process_search_path(argv[0]);
156     if (!binary) {
157         VLOG_ERR("%s not found in PATH", argv[0]);
158         return ENOENT;
159     }
160     free(binary);
161
162     block_sigchld(&oldsigs);
163     fatal_signal_block();
164     pid = fork();
165     if (pid < 0) {
166         fatal_signal_unblock();
167         unblock_sigchld(&oldsigs);
168         VLOG_WARN("fork failed: %s", strerror(errno));
169         return errno;
170     } else if (pid) {
171         /* Running in parent process. */
172         struct process *p;
173         const char *slash;
174
175         p = xcalloc(1, sizeof *p);
176         p->pid = pid;
177         slash = strrchr(argv[0], '/');
178         p->name = xstrdup(slash ? slash + 1 : argv[0]);
179         p->exited = false;
180
181         list_push_back(&all_processes, &p->node);
182         unblock_sigchld(&oldsigs);
183         fatal_signal_unblock();
184
185         *pp = p;
186         return 0;
187     } else {
188         /* Running in child process. */
189         int fd_max = get_max_fds();
190         int fd;
191
192         fatal_signal_fork();
193         fatal_signal_unblock();
194         unblock_sigchld(&oldsigs);
195         for (fd = 0; fd < fd_max; fd++) {
196             if (is_member(fd, null_fds, n_null_fds)) {
197                 /* We can't use get_null_fd() here because we might have
198                  * already closed its fd. */
199                 int nullfd = open("/dev/null", O_RDWR);
200                 dup2(nullfd, fd);
201                 close(nullfd);
202             } else if (fd >= 3 && !is_member(fd, keep_fds, n_keep_fds)) {
203                 close(fd);
204             }
205         }
206         execvp(argv[0], argv);
207         fprintf(stderr, "execvp(\"%s\") failed: %s\n",
208                 argv[0], strerror(errno));
209         _exit(1);
210     }
211 }
212
213 /* Destroys process 'p'. */
214 void
215 process_destroy(struct process *p)
216 {
217     if (p) {
218         sigset_t oldsigs;
219
220         block_sigchld(&oldsigs);
221         list_remove(&p->node);
222         unblock_sigchld(&oldsigs);
223
224         free(p->name);
225         free(p);
226     }
227 }
228
229 /* Sends signal 'signr' to process 'p'.  Returns 0 if successful, otherwise a
230  * positive errno value. */
231 int
232 process_kill(const struct process *p, int signr)
233 {
234     return (p->exited ? ESRCH
235             : !kill(p->pid, signr) ? 0
236             : errno);
237 }
238
239 /* Returns the pid of process 'p'. */
240 pid_t
241 process_pid(const struct process *p)
242 {
243     return p->pid;
244 }
245
246 /* Returns the name of process 'p' (the name passed to process_start() with any
247  * leading directories stripped). */
248 const char *
249 process_name(const struct process *p)
250 {
251     return p->name;
252 }
253
254 /* Returns true if process 'p' has exited, false otherwise. */
255 bool
256 process_exited(struct process *p)
257 {
258     if (p->exited) {
259         return true;
260     } else {
261         char buf[_POSIX_PIPE_BUF];
262         read(fds[0], buf, sizeof buf);
263         return false;
264     }
265 }
266
267 /* Returns process 'p''s exit status, as reported by waitpid(2).
268  * process_status(p) may be called only after process_exited(p) has returned
269  * true. */
270 int
271 process_status(const struct process *p)
272 {
273     assert(p->exited);
274     return p->status;
275 }
276
277 int
278 process_run(char **argv,
279             const int keep_fds[], size_t n_keep_fds,
280             const int null_fds[], size_t n_null_fds,
281             int *status)
282 {
283     struct process *p;
284     int retval;
285
286     COVERAGE_INC(process_run);
287     retval = process_start(argv, keep_fds, n_keep_fds, null_fds, n_null_fds,
288                            &p);
289     if (retval) {
290         *status = 0;
291         return retval;
292     }
293
294     while (!process_exited(p)) {
295         process_wait(p);
296         poll_block();
297     }
298     *status = process_status(p);
299     process_destroy(p);
300     return 0;
301 }
302
303 /* Given 'status', which is a process status in the form reported by waitpid(2)
304  * and returned by process_status(), returns a string describing how the
305  * process terminated.  The caller is responsible for freeing the string when
306  * it is no longer needed. */
307 char *
308 process_status_msg(int status)
309 {
310     struct ds ds = DS_EMPTY_INITIALIZER;
311     if (WIFEXITED(status)) {
312         ds_put_format(&ds, "exit status %d", WEXITSTATUS(status));
313     } else if (WIFSIGNALED(status) || WIFSTOPPED(status)) {
314         int signr = WIFSIGNALED(status) ? WTERMSIG(status) : WSTOPSIG(status);
315         const char *name = NULL;
316 #ifdef HAVE_STRSIGNAL
317         name = strsignal(signr);
318 #endif
319         ds_put_format(&ds, "%s by signal %d",
320                       WIFSIGNALED(status) ? "killed" : "stopped", signr);
321         if (name) {
322             ds_put_format(&ds, " (%s)", name);
323         }
324     } else {
325         ds_put_format(&ds, "terminated abnormally (%x)", status);
326     }
327     if (WCOREDUMP(status)) {
328         ds_put_cstr(&ds, ", core dumped");
329     }
330     return ds_cstr(&ds);
331 }
332
333 /* Causes the next call to poll_block() to wake up when process 'p' has
334  * exited. */
335 void
336 process_wait(struct process *p)
337 {
338     if (p->exited) {
339         poll_immediate_wake();
340     } else {
341         poll_fd_wait(fds[0], POLLIN);
342     }
343 }
344
345 char *
346 process_search_path(const char *name)
347 {
348     char *save_ptr = NULL;
349     char *path, *dir;
350     struct stat s;
351
352     if (strchr(name, '/') || !getenv("PATH")) {
353         return stat(name, &s) == 0 ? xstrdup(name) : NULL;
354     }
355
356     path = xstrdup(getenv("PATH"));
357     for (dir = strtok_r(path, ":", &save_ptr); dir;
358          dir = strtok_r(NULL, ":", &save_ptr)) {
359         char *file = xasprintf("%s/%s", dir, name);
360         if (stat(file, &s) == 0) {
361             free(path);
362             return file;
363         }
364         free(file);
365     }
366     free(path);
367     return NULL;
368 }
369 \f
370 static void
371 sigchld_handler(int signr UNUSED)
372 {
373     struct process *p;
374
375     COVERAGE_INC(process_sigchld);
376     LIST_FOR_EACH (p, struct process, node, &all_processes) {
377         if (!p->exited) {
378             int retval, status;
379             do {
380                 retval = waitpid(p->pid, &status, WNOHANG);
381             } while (retval == -1 && errno == EINTR);
382             if (retval == p->pid) {
383                 p->exited = true;
384                 p->status = status;
385             } else if (retval < 0) {
386                 /* XXX We want to log something but we're in a signal
387                  * handler. */
388                 p->exited = true;
389                 p->status = -1;
390             }
391         }
392     }
393     write(fds[1], "", 1);
394 }
395
396 static bool
397 is_member(int x, const int *array, size_t n)
398 {
399     size_t i;
400
401     for (i = 0; i < n; i++) {
402         if (array[i] == x) {
403             return true;
404         }
405     }
406     return false;
407 }
408
409 static void
410 block_sigchld(sigset_t *oldsigs)
411 {
412     sigset_t sigchld;
413     sigemptyset(&sigchld);
414     sigaddset(&sigchld, SIGCHLD);
415     if (sigprocmask(SIG_BLOCK, &sigchld, oldsigs)) {
416         ovs_fatal(errno, "sigprocmask");
417     }
418 }
419
420 static void
421 unblock_sigchld(const sigset_t *oldsigs)
422 {
423     if (sigprocmask(SIG_SETMASK, oldsigs, NULL)) {
424         ovs_fatal(errno, "sigprocmask");
425     }
426 }