087ca6b87da891f639bad04c63954e9c5d110e6c
[sliver-openvswitch.git] / lib / process.c
1 /* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford
2  * Junior University
3  *
4  * We are making the OpenFlow specification and associated documentation
5  * (Software) available for public use and benefit with the expectation
6  * that others will use, modify and enhance the Software and contribute
7  * those enhancements back to the community. However, since we would
8  * like to make the Software available for broadest use, with as few
9  * restrictions as possible permission is hereby granted, free of
10  * charge, to any person obtaining a copy of this Software to deal in
11  * the Software under the copyrights without restriction, including
12  * without limitation the rights to use, copy, modify, merge, publish,
13  * distribute, sublicense, and/or sell copies of the Software, and to
14  * permit persons to whom the Software is furnished to do so, subject to
15  * the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be
18  * included in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE.
28  *
29  * The name and trademarks of copyright holder(s) may NOT be used in
30  * advertising or publicity pertaining to the Software or any
31  * derivatives without specific, written prior permission.
32  */
33
34 #include <config.h>
35 #include "process.h"
36 #include <assert.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <signal.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <sys/stat.h>
43 #include <sys/wait.h>
44 #include <unistd.h>
45 #include "dynamic-string.h"
46 #include "list.h"
47 #include "poll-loop.h"
48 #include "socket-util.h"
49 #include "util.h"
50
51 #define THIS_MODULE VLM_process
52 #include "vlog.h"
53
54 struct process {
55     struct list node;
56     char *name;
57     pid_t pid;
58
59     /* Modified by signal handler. */
60     volatile bool exited;
61     volatile int status;
62 };
63
64 /* Pipe used to signal child termination. */
65 static int fds[2];
66
67 /* All processes. */
68 static struct list all_processes = LIST_INITIALIZER(&all_processes);
69
70 static void block_sigchld(sigset_t *);
71 static void unblock_sigchld(const sigset_t *);
72 static void sigchld_handler(int signr UNUSED);
73 static bool is_member(int x, const int *array, size_t);
74 static bool find_in_path(const char *name);
75
76 /* Initializes the process subsystem (if it is not already initialized).  Calls
77  * exit() if initialization fails.
78  *
79  * Calling this function is optional; it will be called automatically by
80  * process_start() if necessary.  Calling it explicitly allows the client to
81  * prevent the process from exiting at an unexpected time. */
82 void
83 process_init(void)
84 {
85     static bool inited;
86     struct sigaction sa;
87
88     if (inited) {
89         return;
90     }
91     inited = true;
92
93     /* Create notification pipe. */
94     if (pipe(fds)) {
95         ofp_fatal(errno, "could not create pipe");
96     }
97     set_nonblocking(fds[0]);
98     set_nonblocking(fds[1]);
99
100     /* Set up child termination signal handler. */
101     memset(&sa, 0, sizeof sa);
102     sa.sa_handler = sigchld_handler;
103     sigemptyset(&sa.sa_mask);
104     sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
105     if (sigaction(SIGCHLD, &sa, NULL)) {
106         ofp_fatal(errno, "sigaction(SIGCHLD) failed");
107     }
108 }
109
110 /* Starts a subprocess with the arguments in the null-terminated argv[] array.
111  * argv[0] is used as the name of the process.  Searches the PATH environment
112  * variable to find the program to execute.
113  *
114  * All file descriptors are closed before executing the subprocess, except for
115  * fds 0, 1, and 2 and the 'n_keep_fds' fds listed in 'keep_fds'.  Also, any of
116  * the 'n_null_fds' fds listed in 'null_fds' are replaced by /dev/null.
117  *
118  * Returns 0 if successful, otherwise a positive errno value indicating the
119  * error.  If successful, '*pp' is assigned a new struct process that may be
120  * used to query the process's status.  On failure, '*pp' is set to NULL. */
121 int
122 process_start(char **argv,
123               const int keep_fds[], size_t n_keep_fds,
124               const int null_fds[], size_t n_null_fds,
125               struct process **pp)
126 {
127     sigset_t oldsigs;
128     pid_t pid;
129
130     *pp = NULL;
131     process_init();
132
133     if (VLOG_IS_DBG_ENABLED()) {
134         struct ds ds = DS_EMPTY_INITIALIZER;
135         char **argp;
136         for (argp = argv; *argp; argp++) {
137             const char *arg = *argp;
138             const char *p;
139             if (argp != argv) {
140                 ds_put_char(&ds, ' ');
141             }
142             if (arg[strcspn(arg, " \t\r\n\v\\")]) {
143                 ds_put_char(&ds, '"');
144                 for (p = arg; *p; p++) {
145                     if (*p == '\\' || *p == '\"') {
146                         ds_put_char(&ds, '\\');
147                     }
148                     ds_put_char(&ds, *p);
149                 }
150                 ds_put_char(&ds, '"');
151             } else {
152                 ds_put_cstr(&ds, arg);
153             }
154         }
155         VLOG_DBG("starting subprocess: %s", ds_cstr(&ds));
156         ds_destroy(&ds);
157     }
158
159     /* execvp() will search PATH too, but the error in that case is more
160      * obscure, since it is only reported post-fork. */
161     if (!find_in_path(argv[0])) {
162         VLOG_ERR("%s not found in PATH", argv[0]);
163         return ENOENT;
164     }
165
166     block_sigchld(&oldsigs);
167     pid = fork();
168     if (pid < 0) {
169         unblock_sigchld(&oldsigs);
170         VLOG_WARN("fork failed: %s", strerror(errno));
171         return errno;
172     } else if (pid) {
173         /* Running in parent process. */
174         struct process *p;
175         const char *slash;
176
177         p = xcalloc(1, sizeof *p);
178         p->pid = pid;
179         slash = strrchr(argv[0], '/');
180         p->name = xstrdup(slash ? slash + 1 : argv[0]);
181         p->exited = false;
182
183         list_push_back(&all_processes, &p->node);
184         unblock_sigchld(&oldsigs);
185
186         *pp = p;
187         return 0;
188     } else {
189         /* Running in child process. */
190         int fd_max = get_max_fds();
191         int fd;
192
193         unblock_sigchld(&oldsigs);
194         for (fd = 0; fd < fd_max; fd++) {
195             if (is_member(fd, null_fds, n_null_fds)) {
196                 int nullfd = open("/dev/null", O_RDWR);
197                 dup2(nullfd, fd);
198                 close(nullfd);
199             } else if (fd >= 3 && !is_member(fd, keep_fds, n_keep_fds)) {
200                 close(fd);
201             }
202         }
203         execvp(argv[0], argv);
204         fprintf(stderr, "execvp(\"%s\") failed: %s\n",
205                 argv[0], strerror(errno));
206         _exit(1);
207     }
208 }
209
210 /* Destroys process 'p'. */
211 void
212 process_destroy(struct process *p)
213 {
214     if (p) {
215         sigset_t oldsigs;
216
217         block_sigchld(&oldsigs);
218         list_remove(&p->node);
219         unblock_sigchld(&oldsigs);
220
221         free(p->name);
222         free(p);
223     }
224 }
225
226 /* Sends signal 'signr' to process 'p'.  Returns 0 if successful, otherwise a
227  * positive errno value. */
228 int
229 process_kill(const struct process *p, int signr)
230 {
231     return (p->exited ? ESRCH
232             : !kill(p->pid, signr) ? 0
233             : errno);
234 }
235
236 /* Returns the pid of process 'p'. */
237 pid_t
238 process_pid(const struct process *p)
239 {
240     return p->pid;
241 }
242
243 /* Returns the name of process 'p' (the name passed to process_start() with any
244  * leading directories stripped). */
245 const char *
246 process_name(const struct process *p)
247 {
248     return p->name;
249 }
250
251 /* Returns true if process 'p' has exited, false otherwise. */
252 bool
253 process_exited(struct process *p)
254 {
255     if (p->exited) {
256         return true;
257     } else {
258         char buf[_POSIX_PIPE_BUF];
259         read(fds[0], buf, sizeof buf);
260         return false;
261     }
262 }
263
264 /* Returns process 'p''s exit status, as reported by waitpid(2).
265  * process_status(p) may be called only after process_exited(p) has returned
266  * true. */
267 int
268 process_status(const struct process *p)
269 {
270     assert(p->exited);
271     return p->status;
272 }
273
274 int
275 process_run(char **argv,
276             const int keep_fds[], size_t n_keep_fds,
277             const int null_fds[], size_t n_null_fds,
278             int *status)
279 {
280     struct process *p;
281     int retval;
282
283     retval = process_start(argv, keep_fds, n_keep_fds, null_fds, n_null_fds,
284                            &p);
285     if (retval) {
286         *status = 0;
287         return retval;
288     }
289
290     while (!process_exited(p)) {
291         process_wait(p);
292         poll_block();
293     }
294     *status = process_status(p);
295     process_destroy(p);
296     return 0;
297 }
298
299 /* Given 'status', which is a process status in the form reported by waitpid(2)
300  * and returned by process_status(), returns a string describing how the
301  * process terminated.  The caller is responsible for freeing the string when
302  * it is no longer needed. */
303 char *
304 process_status_msg(int status)
305 {
306     struct ds ds = DS_EMPTY_INITIALIZER;
307     if (WIFEXITED(status)) {
308         ds_put_format(&ds, "exit status %d", WEXITSTATUS(status));
309     } else if (WIFSIGNALED(status)) {
310         const char *name = NULL;
311 #ifdef HAVE_STRSIGNAL
312         name = strsignal(WTERMSIG(status));
313 #endif
314         ds_put_format(&ds, "killed by signal %d", WTERMSIG(status));
315         if (name) {
316             ds_put_format(&ds, " (%s)", name);
317         }
318     }
319     if (WCOREDUMP(status)) {
320         ds_put_cstr(&ds, ", core dumped");
321     }
322     return ds_cstr(&ds);
323 }
324
325 /* Causes the next call to poll_block() to wake up when process 'p' has
326  * exited. */
327 void
328 process_wait(struct process *p)
329 {
330     if (p->exited) {
331         poll_immediate_wake();
332     } else {
333         poll_fd_wait(fds[0], POLLIN);
334     }
335 }
336 \f
337 static void
338 sigchld_handler(int signr UNUSED)
339 {
340     struct process *p;
341
342     LIST_FOR_EACH (p, struct process, node, &all_processes) {
343         if (!p->exited) {
344             int retval, status;
345             do {
346                 retval = waitpid(p->pid, &status, WNOHANG);
347             } while (retval == -1 && errno == EINTR);
348             if (retval == p->pid) {
349                 p->exited = true;
350                 p->status = status;
351             } else if (retval < 0) {
352                 /* XXX We want to log something but we're in a signal
353                  * handler. */
354                 p->exited = true;
355                 p->status = -1;
356             }
357         }
358     }
359     write(fds[1], "", 1);
360 }
361
362 static bool
363 is_member(int x, const int *array, size_t n)
364 {
365     size_t i;
366
367     for (i = 0; i < n; i++) {
368         if (array[i] == x) {
369             return true;
370         }
371     }
372     return false;
373 }
374
375 static void
376 block_sigchld(sigset_t *oldsigs)
377 {
378     sigset_t sigchld;
379     sigemptyset(&sigchld);
380     sigaddset(&sigchld, SIGCHLD);
381     if (sigprocmask(SIG_BLOCK, &sigchld, oldsigs)) {
382         ofp_fatal(errno, "sigprocmask");
383     }
384 }
385
386 static void
387 unblock_sigchld(const sigset_t *oldsigs)
388 {
389     if (sigprocmask(SIG_SETMASK, oldsigs, NULL)) {
390         ofp_fatal(errno, "sigprocmask");
391     }
392 }
393
394 static bool
395 find_in_path(const char *name)
396 {
397     char *save_ptr = NULL;
398     char *path, *dir;
399     struct stat s;
400
401     if (strchr(name, '/') || !getenv("PATH")) {
402         return stat(name, &s) == 0;
403     }
404
405     path = xstrdup(getenv("PATH"));
406     for (dir = strtok_r(path, ":", &save_ptr); dir;
407          dir = strtok_r(NULL, ":", &save_ptr)) {
408         char *file = xasprintf("%s/%s", dir, name);
409         if (stat(file, &s) == 0) {
410             free(file);
411             free(path);
412             return true;
413         }
414         free(file);
415     }
416     free(path);
417     return false;
418 }