process: Make signal handling thread-safe.
[sliver-openvswitch.git] / lib / process.c
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
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 <errno.h>
20 #include <fcntl.h>
21 #include <signal.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/stat.h>
25 #include <sys/wait.h>
26 #include <unistd.h>
27 #include "coverage.h"
28 #include "dynamic-string.h"
29 #include "fatal-signal.h"
30 #include "list.h"
31 #include "poll-loop.h"
32 #include "signals.h"
33 #include "socket-util.h"
34 #include "util.h"
35 #include "vlog.h"
36
37 VLOG_DEFINE_THIS_MODULE(process);
38
39 COVERAGE_DEFINE(process_sigchld);
40 COVERAGE_DEFINE(process_start);
41
42 struct process {
43     struct list node;
44     char *name;
45     pid_t pid;
46
47     /* State. */
48     bool exited;
49     int status;
50 };
51
52 /* Pipe used to signal child termination. */
53 static int fds[2];
54
55 /* All processes. */
56 static struct list all_processes = LIST_INITIALIZER(&all_processes);
57
58 static void sigchld_handler(int signr OVS_UNUSED);
59
60 /* Initializes the process subsystem (if it is not already initialized).  Calls
61  * exit() if initialization fails.
62  *
63  * Calling this function is optional; it will be called automatically by
64  * process_start() if necessary.  Calling it explicitly allows the client to
65  * prevent the process from exiting at an unexpected time. */
66 void
67 process_init(void)
68 {
69     static bool inited;
70     struct sigaction sa;
71
72     if (inited) {
73         return;
74     }
75     inited = true;
76
77     /* Create notification pipe. */
78     xpipe_nonblocking(fds);
79
80     /* Set up child termination signal handler. */
81     memset(&sa, 0, sizeof sa);
82     sa.sa_handler = sigchld_handler;
83     sigemptyset(&sa.sa_mask);
84     sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
85     xsigaction(SIGCHLD, &sa, NULL);
86 }
87
88 char *
89 process_escape_args(char **argv)
90 {
91     struct ds ds = DS_EMPTY_INITIALIZER;
92     char **argp;
93     for (argp = argv; *argp; argp++) {
94         const char *arg = *argp;
95         const char *p;
96         if (argp != argv) {
97             ds_put_char(&ds, ' ');
98         }
99         if (arg[strcspn(arg, " \t\r\n\v\\\'\"")]) {
100             ds_put_char(&ds, '"');
101             for (p = arg; *p; p++) {
102                 if (*p == '\\' || *p == '\"') {
103                     ds_put_char(&ds, '\\');
104                 }
105                 ds_put_char(&ds, *p);
106             }
107             ds_put_char(&ds, '"');
108         } else {
109             ds_put_cstr(&ds, arg);
110         }
111     }
112     return ds_cstr(&ds);
113 }
114
115 /* Prepare to start a process whose command-line arguments are given by the
116  * null-terminated 'argv' array.  Returns 0 if successful, otherwise a
117  * positive errno value. */
118 static int
119 process_prestart(char **argv)
120 {
121     char *binary;
122
123     process_init();
124
125     /* Log the process to be started. */
126     if (VLOG_IS_DBG_ENABLED()) {
127         char *args = process_escape_args(argv);
128         VLOG_DBG("starting subprocess: %s", args);
129         free(args);
130     }
131
132     /* execvp() will search PATH too, but the error in that case is more
133      * obscure, since it is only reported post-fork. */
134     binary = process_search_path(argv[0]);
135     if (!binary) {
136         VLOG_ERR("%s not found in PATH", argv[0]);
137         return ENOENT;
138     }
139     free(binary);
140
141     return 0;
142 }
143
144 /* Creates and returns a new struct process with the specified 'name' and
145  * 'pid'. */
146 static struct process *
147 process_register(const char *name, pid_t pid)
148 {
149     struct process *p;
150     const char *slash;
151
152     p = xzalloc(sizeof *p);
153     p->pid = pid;
154     slash = strrchr(name, '/');
155     p->name = xstrdup(slash ? slash + 1 : name);
156     p->exited = false;
157
158     list_push_back(&all_processes, &p->node);
159
160     return p;
161 }
162
163 /* Starts a subprocess with the arguments in the null-terminated argv[] array.
164  * argv[0] is used as the name of the process.  Searches the PATH environment
165  * variable to find the program to execute.
166  *
167  * All file descriptors are closed before executing the subprocess, except for
168  * fds 0, 1, and 2.
169  *
170  * Returns 0 if successful, otherwise a positive errno value indicating the
171  * error.  If successful, '*pp' is assigned a new struct process that may be
172  * used to query the process's status.  On failure, '*pp' is set to NULL. */
173 int
174 process_start(char **argv, struct process **pp)
175 {
176     pid_t pid;
177     int error;
178
179     *pp = NULL;
180     COVERAGE_INC(process_start);
181     error = process_prestart(argv);
182     if (error) {
183         return error;
184     }
185
186     pid = fork();
187     if (pid < 0) {
188         VLOG_WARN("fork failed: %s", strerror(errno));
189         return errno;
190     } else if (pid) {
191         /* Running in parent process. */
192         *pp = process_register(argv[0], pid);
193         return 0;
194     } else {
195         /* Running in child process. */
196         int fd_max = get_max_fds();
197         int fd;
198
199         fatal_signal_fork();
200         for (fd = 3; fd < fd_max; fd++) {
201             close(fd);
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         list_remove(&p->node);
216         free(p->name);
217         free(p);
218     }
219 }
220
221 /* Sends signal 'signr' to process 'p'.  Returns 0 if successful, otherwise a
222  * positive errno value. */
223 int
224 process_kill(const struct process *p, int signr)
225 {
226     return (p->exited ? ESRCH
227             : !kill(p->pid, signr) ? 0
228             : errno);
229 }
230
231 /* Returns the pid of process 'p'. */
232 pid_t
233 process_pid(const struct process *p)
234 {
235     return p->pid;
236 }
237
238 /* Returns the name of process 'p' (the name passed to process_start() with any
239  * leading directories stripped). */
240 const char *
241 process_name(const struct process *p)
242 {
243     return p->name;
244 }
245
246 /* Returns true if process 'p' has exited, false otherwise. */
247 bool
248 process_exited(struct process *p)
249 {
250     return p->exited;
251 }
252
253 /* Returns process 'p''s exit status, as reported by waitpid(2).
254  * process_status(p) may be called only after process_exited(p) has returned
255  * true. */
256 int
257 process_status(const struct process *p)
258 {
259     ovs_assert(p->exited);
260     return p->status;
261 }
262
263 /* Given 'status', which is a process status in the form reported by waitpid(2)
264  * and returned by process_status(), returns a string describing how the
265  * process terminated.  The caller is responsible for freeing the string when
266  * it is no longer needed. */
267 char *
268 process_status_msg(int status)
269 {
270     struct ds ds = DS_EMPTY_INITIALIZER;
271     if (WIFEXITED(status)) {
272         ds_put_format(&ds, "exit status %d", WEXITSTATUS(status));
273     } else if (WIFSIGNALED(status)) {
274         char namebuf[SIGNAL_NAME_BUFSIZE];
275
276         ds_put_format(&ds, "killed (%s)",
277                       signal_name(WTERMSIG(status), namebuf, sizeof namebuf));
278     } else if (WIFSTOPPED(status)) {
279         char namebuf[SIGNAL_NAME_BUFSIZE];
280
281         ds_put_format(&ds, "stopped (%s)",
282                       signal_name(WSTOPSIG(status), namebuf, sizeof namebuf));
283     } else {
284         ds_put_format(&ds, "terminated abnormally (%x)", status);
285     }
286     if (WCOREDUMP(status)) {
287         ds_put_cstr(&ds, ", core dumped");
288     }
289     return ds_cstr(&ds);
290 }
291
292 /* Executes periodic maintenance activities required by the process module. */
293 void
294 process_run(void)
295 {
296     char buf[_POSIX_PIPE_BUF];
297
298     if (!list_is_empty(&all_processes) && read(fds[0], buf, sizeof buf) > 0) {
299         struct process *p;
300
301         LIST_FOR_EACH (p, node, &all_processes) {
302             if (!p->exited) {
303                 int retval, status;
304                 do {
305                     retval = waitpid(p->pid, &status, WNOHANG);
306                 } while (retval == -1 && errno == EINTR);
307                 if (retval == p->pid) {
308                     p->exited = true;
309                     p->status = status;
310                 } else if (retval < 0) {
311                     VLOG_WARN("waitpid: %s", strerror(errno));
312                     p->exited = true;
313                     p->status = -1;
314                 }
315             }
316         }
317     }
318 }
319
320
321 /* Causes the next call to poll_block() to wake up when process 'p' has
322  * exited. */
323 void
324 process_wait(struct process *p)
325 {
326     if (p->exited) {
327         poll_immediate_wake();
328     } else {
329         poll_fd_wait(fds[0], POLLIN);
330     }
331 }
332
333 char *
334 process_search_path(const char *name)
335 {
336     char *save_ptr = NULL;
337     char *path, *dir;
338     struct stat s;
339
340     if (strchr(name, '/') || !getenv("PATH")) {
341         return stat(name, &s) == 0 ? xstrdup(name) : NULL;
342     }
343
344     path = xstrdup(getenv("PATH"));
345     for (dir = strtok_r(path, ":", &save_ptr); dir;
346          dir = strtok_r(NULL, ":", &save_ptr)) {
347         char *file = xasprintf("%s/%s", dir, name);
348         if (stat(file, &s) == 0) {
349             free(path);
350             return file;
351         }
352         free(file);
353     }
354     free(path);
355     return NULL;
356 }
357 \f
358 static void
359 sigchld_handler(int signr OVS_UNUSED)
360 {
361     ignore(write(fds[1], "", 1));
362 }