Branch data Line data Source code
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/resource.h>
25 : : #include <sys/stat.h>
26 : : #include <sys/wait.h>
27 : : #include <unistd.h>
28 : : #include "coverage.h"
29 : : #include "openvswitch/dynamic-string.h"
30 : : #include "fatal-signal.h"
31 : : #include "openvswitch/list.h"
32 : : #include "ovs-thread.h"
33 : : #include "poll-loop.h"
34 : : #include "signals.h"
35 : : #include "socket-util.h"
36 : : #include "util.h"
37 : : #include "openvswitch/vlog.h"
38 : :
39 : 50274 : VLOG_DEFINE_THIS_MODULE(process);
40 : :
41 : 138984 : COVERAGE_DEFINE(process_start);
42 : :
43 : : struct process {
44 : : struct ovs_list node;
45 : : char *name;
46 : : pid_t pid;
47 : :
48 : : /* State. */
49 : : bool exited;
50 : : int status;
51 : : };
52 : :
53 : : /* Pipe used to signal child termination. */
54 : : static int fds[2];
55 : :
56 : : /* All processes. */
57 : : static struct ovs_list all_processes = OVS_LIST_INITIALIZER(&all_processes);
58 : :
59 : : static void sigchld_handler(int signr OVS_UNUSED);
60 : :
61 : : /* Initializes the process subsystem (if it is not already initialized). Calls
62 : : * exit() if initialization fails.
63 : : *
64 : : * This function may not be called after creating any additional threads.
65 : : *
66 : : * Calling this function is optional; it will be called automatically by
67 : : * process_start() if necessary. Calling it explicitly allows the client to
68 : : * prevent the process from exiting at an unexpected time. */
69 : : void
70 : 1405 : process_init(void)
71 : : {
72 : : #ifndef _WIN32
73 : : static bool inited;
74 : : struct sigaction sa;
75 : :
76 : 1405 : assert_single_threaded();
77 [ + + ]: 1405 : if (inited) {
78 : 108 : return;
79 : : }
80 : 1297 : inited = true;
81 : :
82 : : /* Create notification pipe. */
83 : 1297 : xpipe_nonblocking(fds);
84 : :
85 : : /* Set up child termination signal handler. */
86 : 1297 : memset(&sa, 0, sizeof sa);
87 : 1297 : sa.sa_handler = sigchld_handler;
88 : 1297 : sigemptyset(&sa.sa_mask);
89 : 1297 : sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
90 : 1297 : xsigaction(SIGCHLD, &sa, NULL);
91 : : #endif
92 : : }
93 : :
94 : : char *
95 : 6460 : process_escape_args(char **argv)
96 : : {
97 : 6460 : struct ds ds = DS_EMPTY_INITIALIZER;
98 : : char **argp;
99 [ + + ]: 67467 : for (argp = argv; *argp; argp++) {
100 : 61007 : const char *arg = *argp;
101 : : const char *p;
102 [ + + ]: 61007 : if (argp != argv) {
103 : 54547 : ds_put_char(&ds, ' ');
104 : : }
105 [ + + ]: 61007 : if (arg[strcspn(arg, " \t\r\n\v\\\'\"")]) {
106 : 719 : ds_put_char(&ds, '"');
107 [ + + ]: 86000 : for (p = arg; *p; p++) {
108 [ + + ][ + + ]: 85281 : if (*p == '\\' || *p == '\"') {
109 : 308 : ds_put_char(&ds, '\\');
110 : : }
111 : 85281 : ds_put_char(&ds, *p);
112 : : }
113 : 719 : ds_put_char(&ds, '"');
114 : : } else {
115 : 60288 : ds_put_cstr(&ds, arg);
116 : : }
117 : : }
118 : 6460 : return ds_cstr(&ds);
119 : : }
120 : :
121 : : /* Prepare to start a process whose command-line arguments are given by the
122 : : * null-terminated 'argv' array. Returns 0 if successful, otherwise a
123 : : * positive errno value. */
124 : : static int
125 : 108 : process_prestart(char **argv)
126 : : {
127 : : char *binary;
128 : :
129 : 108 : process_init();
130 : :
131 : : /* Log the process to be started. */
132 [ - + ]: 108 : if (VLOG_IS_DBG_ENABLED()) {
133 : 0 : char *args = process_escape_args(argv);
134 [ # # ]: 0 : VLOG_DBG("starting subprocess: %s", args);
135 : 0 : free(args);
136 : : }
137 : :
138 : : /* execvp() will search PATH too, but the error in that case is more
139 : : * obscure, since it is only reported post-fork. */
140 : 108 : binary = process_search_path(argv[0]);
141 [ - + ]: 108 : if (!binary) {
142 [ # # ]: 0 : VLOG_ERR("%s not found in PATH", argv[0]);
143 : 0 : return ENOENT;
144 : : }
145 : 108 : free(binary);
146 : :
147 : 108 : return 0;
148 : : }
149 : :
150 : : /* Creates and returns a new struct process with the specified 'name' and
151 : : * 'pid'. */
152 : : static struct process *
153 : 108 : process_register(const char *name, pid_t pid)
154 : : {
155 : : struct process *p;
156 : : const char *slash;
157 : :
158 : 108 : p = xzalloc(sizeof *p);
159 : 108 : p->pid = pid;
160 : 108 : slash = strrchr(name, '/');
161 [ + - ]: 108 : p->name = xstrdup(slash ? slash + 1 : name);
162 : 108 : p->exited = false;
163 : :
164 : 108 : ovs_list_push_back(&all_processes, &p->node);
165 : :
166 : 108 : return p;
167 : : }
168 : :
169 : : #ifndef _WIN32
170 : : static bool
171 : 108 : rlim_is_finite(rlim_t limit)
172 : : {
173 [ - + ]: 108 : if (limit == RLIM_INFINITY) {
174 : 0 : return false;
175 : : }
176 : :
177 : : #ifdef RLIM_SAVED_CUR /* FreeBSD 8.0 lacks RLIM_SAVED_CUR. */
178 [ - + ]: 108 : if (limit == RLIM_SAVED_CUR) {
179 : 0 : return false;
180 : : }
181 : : #endif
182 : :
183 : : #ifdef RLIM_SAVED_MAX /* FreeBSD 8.0 lacks RLIM_SAVED_MAX. */
184 [ - + ]: 108 : if (limit == RLIM_SAVED_MAX) {
185 : 0 : return false;
186 : : }
187 : : #endif
188 : :
189 : 108 : return true;
190 : : }
191 : :
192 : : /* Returns the maximum valid FD value, plus 1. */
193 : : static int
194 : 108 : get_max_fds(void)
195 : : {
196 : : static int max_fds;
197 : :
198 [ + - ]: 108 : if (!max_fds) {
199 : : struct rlimit r;
200 [ + - ][ + - ]: 108 : if (!getrlimit(RLIMIT_NOFILE, &r) && rlim_is_finite(r.rlim_cur)) {
201 : 108 : max_fds = r.rlim_cur;
202 : : } else {
203 [ # # ]: 0 : VLOG_WARN("failed to obtain fd limit, defaulting to 1024");
204 : 108 : max_fds = 1024;
205 : : }
206 : : }
207 : :
208 : 108 : return max_fds;
209 : : }
210 : : #endif /* _WIN32 */
211 : :
212 : : /* Starts a subprocess with the arguments in the null-terminated argv[] array.
213 : : * argv[0] is used as the name of the process. Searches the PATH environment
214 : : * variable to find the program to execute.
215 : : *
216 : : * This function may not be called after creating any additional threads.
217 : : *
218 : : * All file descriptors are closed before executing the subprocess, except for
219 : : * fds 0, 1, and 2.
220 : : *
221 : : * Returns 0 if successful, otherwise a positive errno value indicating the
222 : : * error. If successful, '*pp' is assigned a new struct process that may be
223 : : * used to query the process's status. On failure, '*pp' is set to NULL. */
224 : : int
225 : 108 : process_start(char **argv, struct process **pp)
226 : : {
227 : : #ifndef _WIN32
228 : : pid_t pid;
229 : : int error;
230 : : sigset_t prev_mask;
231 : :
232 : 108 : assert_single_threaded();
233 : :
234 : 108 : *pp = NULL;
235 : 108 : COVERAGE_INC(process_start);
236 : 108 : error = process_prestart(argv);
237 [ - + ]: 108 : if (error) {
238 : 0 : return error;
239 : : }
240 : :
241 : 108 : fatal_signal_block(&prev_mask);
242 : 108 : pid = fork();
243 [ - + ]: 216 : if (pid < 0) {
244 [ # # ]: 0 : VLOG_WARN("fork failed: %s", ovs_strerror(errno));
245 : 0 : error = errno;
246 [ + + ]: 216 : } else if (pid) {
247 : : /* Running in parent process. */
248 : 108 : *pp = process_register(argv[0], pid);
249 : 108 : error = 0;
250 : : } else {
251 : : /* Running in child process. */
252 : 108 : int fd_max = get_max_fds();
253 : : int fd;
254 : :
255 : 108 : fatal_signal_fork();
256 [ + + ]: 110376 : for (fd = 3; fd < fd_max; fd++) {
257 : 110268 : close(fd);
258 : : }
259 : 108 : xpthread_sigmask(SIG_SETMASK, &prev_mask, NULL);
260 : 108 : execvp(argv[0], argv);
261 : 0 : fprintf(stderr, "execvp(\"%s\") failed: %s\n",
262 : 108 : argv[0], ovs_strerror(errno));
263 : 0 : _exit(1);
264 : : }
265 : 108 : xpthread_sigmask(SIG_SETMASK, &prev_mask, NULL);
266 : 108 : return error;
267 : : #else
268 : : *pp = NULL;
269 : : return ENOSYS;
270 : : #endif
271 : : }
272 : :
273 : : /* Destroys process 'p'. */
274 : : void
275 : 0 : process_destroy(struct process *p)
276 : : {
277 [ # # ]: 0 : if (p) {
278 : 0 : ovs_list_remove(&p->node);
279 : 0 : free(p->name);
280 : 0 : free(p);
281 : : }
282 : 0 : }
283 : :
284 : : /* Sends signal 'signr' to process 'p'. Returns 0 if successful, otherwise a
285 : : * positive errno value. */
286 : : int
287 : 0 : process_kill(const struct process *p, int signr)
288 : : {
289 : : #ifndef _WIN32
290 : 0 : return (p->exited ? ESRCH
291 [ # # ]: 0 : : !kill(p->pid, signr) ? 0
292 [ # # ]: 0 : : errno);
293 : : #else
294 : : return ENOSYS;
295 : : #endif
296 : : }
297 : :
298 : : /* Returns the pid of process 'p'. */
299 : : pid_t
300 : 0 : process_pid(const struct process *p)
301 : : {
302 : 0 : return p->pid;
303 : : }
304 : :
305 : : /* Returns the name of process 'p' (the name passed to process_start() with any
306 : : * leading directories stripped). */
307 : : const char *
308 : 0 : process_name(const struct process *p)
309 : : {
310 : 0 : return p->name;
311 : : }
312 : :
313 : : /* Returns true if process 'p' has exited, false otherwise. */
314 : : bool
315 : 831 : process_exited(struct process *p)
316 : : {
317 : 831 : return p->exited;
318 : : }
319 : :
320 : : /* Returns process 'p''s exit status, as reported by waitpid(2).
321 : : * process_status(p) may be called only after process_exited(p) has returned
322 : : * true. */
323 : : int
324 : 108 : process_status(const struct process *p)
325 : : {
326 [ - + ]: 108 : ovs_assert(p->exited);
327 : 108 : return p->status;
328 : : }
329 : :
330 : : /* Given 'status', which is a process status in the form reported by waitpid(2)
331 : : * and returned by process_status(), returns a string describing how the
332 : : * process terminated. The caller is responsible for freeing the string when
333 : : * it is no longer needed. */
334 : : char *
335 : 12 : process_status_msg(int status)
336 : : {
337 : 12 : struct ds ds = DS_EMPTY_INITIALIZER;
338 : : #ifndef _WIN32
339 [ + + ]: 12 : if (WIFEXITED(status)) {
340 : 4 : ds_put_format(&ds, "exit status %d", WEXITSTATUS(status));
341 [ + - ]: 8 : } else if (WIFSIGNALED(status)) {
342 : : char namebuf[SIGNAL_NAME_BUFSIZE];
343 : :
344 : 8 : ds_put_format(&ds, "killed (%s)",
345 : 8 : signal_name(WTERMSIG(status), namebuf, sizeof namebuf));
346 [ # # ]: 0 : } else if (WIFSTOPPED(status)) {
347 : : char namebuf[SIGNAL_NAME_BUFSIZE];
348 : :
349 : 0 : ds_put_format(&ds, "stopped (%s)",
350 : 0 : signal_name(WSTOPSIG(status), namebuf, sizeof namebuf));
351 : : } else {
352 : 0 : ds_put_format(&ds, "terminated abnormally (%x)", status);
353 : : }
354 [ + + ]: 12 : if (WCOREDUMP(status)) {
355 : 6 : ds_put_cstr(&ds, ", core dumped");
356 : : }
357 : : #else
358 : : ds_put_cstr(&ds, "function not supported.");
359 : : #endif
360 : 12 : return ds_cstr(&ds);
361 : : }
362 : :
363 : : /* Executes periodic maintenance activities required by the process module. */
364 : : void
365 : 723 : process_run(void)
366 : : {
367 : : #ifndef _WIN32
368 : : char buf[_POSIX_PIPE_BUF];
369 : :
370 [ + - ][ + + ]: 723 : if (!ovs_list_is_empty(&all_processes) && read(fds[0], buf, sizeof buf) > 0) {
371 : : struct process *p;
372 : :
373 [ + + ]: 216 : LIST_FOR_EACH (p, node, &all_processes) {
374 [ + - ]: 108 : if (!p->exited) {
375 : : int retval, status;
376 : : do {
377 : 108 : retval = waitpid(p->pid, &status, WNOHANG);
378 [ - + ][ # # ]: 108 : } while (retval == -1 && errno == EINTR);
379 [ + - ]: 108 : if (retval == p->pid) {
380 : 108 : p->exited = true;
381 : 108 : p->status = status;
382 [ # # ]: 0 : } else if (retval < 0) {
383 [ # # ]: 0 : VLOG_WARN("waitpid: %s", ovs_strerror(errno));
384 : 0 : p->exited = true;
385 : 108 : p->status = -1;
386 : : }
387 : : }
388 : : }
389 : : }
390 : : #endif
391 : 723 : }
392 : :
393 : :
394 : : /* Causes the next call to poll_block() to wake up when process 'p' has
395 : : * exited. */
396 : : void
397 : 723 : process_wait(struct process *p)
398 : : {
399 : : #ifndef _WIN32
400 [ + + ]: 723 : if (p->exited) {
401 : 108 : poll_immediate_wake();
402 : : } else {
403 : 615 : poll_fd_wait(fds[0], POLLIN);
404 : : }
405 : : #else
406 : : OVS_NOT_REACHED();
407 : : #endif
408 : 723 : }
409 : :
410 : : char *
411 : 108 : process_search_path(const char *name)
412 : : {
413 : 108 : char *save_ptr = NULL;
414 : : char *path, *dir;
415 : : struct stat s;
416 : :
417 [ - + ][ # # ]: 108 : if (strchr(name, '/') || !getenv("PATH")) {
418 [ + - ]: 108 : return stat(name, &s) == 0 ? xstrdup(name) : NULL;
419 : : }
420 : :
421 : 0 : path = xstrdup(getenv("PATH"));
422 [ # # ]: 0 : for (dir = strtok_r(path, ":", &save_ptr); dir;
423 : 0 : dir = strtok_r(NULL, ":", &save_ptr)) {
424 : 0 : char *file = xasprintf("%s/%s", dir, name);
425 [ # # ]: 0 : if (stat(file, &s) == 0) {
426 : 0 : free(path);
427 : 0 : return file;
428 : : }
429 : 0 : free(file);
430 : : }
431 : 0 : free(path);
432 : 108 : return NULL;
433 : : }
434 : :
435 : : static void
436 : 123 : sigchld_handler(int signr OVS_UNUSED)
437 : : {
438 : 123 : ignore(write(fds[1], "", 1));
439 : 123 : }
|