X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Fprocess.c;h=795a136d7de06453aafb77f7ab090b3a6f481f6b;hb=485e2766d816a18e1a51ddf5e12e55f38aeedf89;hp=377c396b90cab6871860cf91f8d92a9c9e089a9f;hpb=2a022368f4b37559de5d5621a88c648023493f75;p=sliver-openvswitch.git diff --git a/lib/process.c b/lib/process.c index 377c396b9..795a136d7 100644 --- a/lib/process.c +++ b/lib/process.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009, 2010 Nicira Networks. + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,6 @@ #include #include "process.h" -#include #include #include #include @@ -30,11 +29,17 @@ #include "fatal-signal.h" #include "list.h" #include "poll-loop.h" +#include "signals.h" #include "socket-util.h" #include "util.h" #include "vlog.h" -VLOG_DEFINE_THIS_MODULE(process) +VLOG_DEFINE_THIS_MODULE(process); + +COVERAGE_DEFINE(process_run); +COVERAGE_DEFINE(process_run_capture); +COVERAGE_DEFINE(process_sigchld); +COVERAGE_DEFINE(process_start); struct process { struct list node; @@ -76,20 +81,14 @@ process_init(void) inited = true; /* Create notification pipe. */ - if (pipe(fds)) { - ovs_fatal(errno, "could not create pipe"); - } - set_nonblocking(fds[0]); - set_nonblocking(fds[1]); + xpipe_nonblocking(fds); /* Set up child termination signal handler. */ memset(&sa, 0, sizeof sa); sa.sa_handler = sigchld_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_NOCLDSTOP | SA_RESTART; - if (sigaction(SIGCHLD, &sa, NULL)) { - ovs_fatal(errno, "sigaction(SIGCHLD) failed"); - } + xsigaction(SIGCHLD, &sa, NULL); } char * @@ -159,7 +158,7 @@ process_register(const char *name, pid_t pid) struct process *p; const char *slash; - assert(sigchld_is_blocked()); + ovs_assert(sigchld_is_blocked()); p = xzalloc(sizeof *p); p->pid = pid; @@ -190,6 +189,7 @@ process_start(char **argv, struct process **pp) { sigset_t oldsigs; + int nullfd; pid_t pid; int error; @@ -200,6 +200,15 @@ process_start(char **argv, return error; } + if (n_null_fds) { + nullfd = get_null_fd(); + if (nullfd < 0) { + return -nullfd; + } + } else { + nullfd = -1; + } + block_sigchld(&oldsigs); pid = fork(); if (pid < 0) { @@ -220,15 +229,17 @@ process_start(char **argv, unblock_sigchld(&oldsigs); for (fd = 0; fd < fd_max; fd++) { if (is_member(fd, null_fds, n_null_fds)) { - /* We can't use get_null_fd() here because we might have - * already closed its fd. */ - int nullfd = open("/dev/null", O_RDWR); dup2(nullfd, fd); - close(nullfd); - } else if (fd >= 3 && !is_member(fd, keep_fds, n_keep_fds)) { + } else if (fd >= 3 && fd != nullfd + && !is_member(fd, keep_fds, n_keep_fds)) { close(fd); } } + if (nullfd >= 0 + && !is_member(nullfd, keep_fds, n_keep_fds) + && !is_member(nullfd, null_fds, n_null_fds)) { + close(nullfd); + } execvp(argv[0], argv); fprintf(stderr, "execvp(\"%s\") failed: %s\n", argv[0], strerror(errno)); @@ -296,7 +307,7 @@ process_exited(struct process *p) int process_status(const struct process *p) { - assert(p->exited); + ovs_assert(p->exited); return p->status; } @@ -336,17 +347,10 @@ process_status_msg(int status) struct ds ds = DS_EMPTY_INITIALIZER; if (WIFEXITED(status)) { ds_put_format(&ds, "exit status %d", WEXITSTATUS(status)); - } else if (WIFSIGNALED(status) || WIFSTOPPED(status)) { - int signr = WIFSIGNALED(status) ? WTERMSIG(status) : WSTOPSIG(status); - const char *name = NULL; -#ifdef HAVE_STRSIGNAL - name = strsignal(signr); -#endif - ds_put_format(&ds, "%s by signal %d", - WIFSIGNALED(status) ? "killed" : "stopped", signr); - if (name) { - ds_put_format(&ds, " (%s)", name); - } + } else if (WIFSIGNALED(status)) { + ds_put_format(&ds, "killed (%s)", signal_name(WTERMSIG(status))); + } else if (WIFSTOPPED(status)) { + ds_put_format(&ds, "stopped (%s)", signal_name(WSTOPSIG(status))); } else { ds_put_format(&ds, "terminated abnormally (%x)", status); } @@ -396,20 +400,28 @@ process_search_path(const char *name) /* process_run_capture() and supporting functions. */ struct stream { + size_t max_size; struct ds log; int fds[2]; }; static int -stream_open(struct stream *s) +stream_open(struct stream *s, size_t max_size) { + int error; + + s->max_size = max_size; ds_init(&s->log); if (pipe(s->fds)) { VLOG_WARN("failed to create pipe: %s", strerror(errno)); return errno; } - set_nonblocking(s->fds[0]); - return 0; + error = set_nonblocking(s->fds[0]); + if (error) { + close(s->fds[0]); + close(s->fds[1]); + } + return error; } static void @@ -436,9 +448,9 @@ stream_read(struct stream *s) } break; } - } else if (s->log.length > PROCESS_MAX_CAPTURE) { - VLOG_WARN("subprocess output overflowed %d-byte buffer", - PROCESS_MAX_CAPTURE); + } else if (s->log.length > s->max_size) { + VLOG_WARN("subprocess output overflowed %zu-byte buffer", + s->max_size); break; } } @@ -473,7 +485,7 @@ stream_close(struct stream *s) * '*status'. * * If 'stdout_log' is nonnull, then the subprocess's output to stdout (up to a - * limit of PROCESS_MAX_CAPTURE bytes) is captured in a memory buffer, which + * limit of 'log_max' bytes) is captured in a memory buffer, which * when this function returns 0 is stored as a null-terminated string in * '*stdout_log'. The caller is responsible for freeing '*stdout_log' (by * passing it to free()). When this function returns an error, '*stdout_log' @@ -483,7 +495,7 @@ stream_close(struct stream *s) * that it captures the subprocess's output to stderr. */ int process_run_capture(char **argv, char **stdout_log, char **stderr_log, - int *status) + size_t max_log, int *status) { struct stream s_stdout, s_stderr; sigset_t oldsigs; @@ -503,12 +515,12 @@ process_run_capture(char **argv, char **stdout_log, char **stderr_log, return error; } - error = stream_open(&s_stdout); + error = stream_open(&s_stdout, max_log); if (error) { return error; } - error = stream_open(&s_stderr); + error = stream_open(&s_stderr, max_log); if (error) { stream_close(&s_stdout); return error; @@ -590,7 +602,7 @@ sigchld_handler(int signr OVS_UNUSED) struct process *p; COVERAGE_INC(process_sigchld); - LIST_FOR_EACH (p, struct process, node, &all_processes) { + LIST_FOR_EACH (p, node, &all_processes) { if (!p->exited) { int retval, status; do { @@ -627,9 +639,8 @@ static bool sigchld_is_blocked(void) { sigset_t sigs; - if (sigprocmask(SIG_SETMASK, NULL, &sigs)) { - ovs_fatal(errno, "sigprocmask"); - } + + xsigprocmask(SIG_SETMASK, NULL, &sigs); return sigismember(&sigs, SIGCHLD); } @@ -637,17 +648,14 @@ static void block_sigchld(sigset_t *oldsigs) { sigset_t sigchld; + sigemptyset(&sigchld); sigaddset(&sigchld, SIGCHLD); - if (sigprocmask(SIG_BLOCK, &sigchld, oldsigs)) { - ovs_fatal(errno, "sigprocmask"); - } + xsigprocmask(SIG_BLOCK, &sigchld, oldsigs); } static void unblock_sigchld(const sigset_t *oldsigs) { - if (sigprocmask(SIG_SETMASK, oldsigs, NULL)) { - ovs_fatal(errno, "sigprocmask"); - } + xsigprocmask(SIG_SETMASK, oldsigs, NULL); }