LCOV - code coverage report
Current view: top level - lib - process.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 114 158 72.2 %
Date: 2016-09-14 01:02:56 Functions: 20 24 83.3 %
Branches: 47 94 50.0 %

           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 : }

Generated by: LCOV version 1.12