LCOV - code coverage report
Current view: top level - utils - start-stop-daemon.c (source / functions) Hit Total Coverage
Test: dpkg 1.21.11 C code coverage Lines: 0 971 0.0 %
Date: 2022-12-03 00:40:01 Functions: 0 61 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 662 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * A rewrite of the original Debian's start-stop-daemon Perl script
       3                 :            :  * in C (faster - it is executed many times during system startup).
       4                 :            :  *
       5                 :            :  * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
       6                 :            :  * public domain.  Based conceptually on start-stop-daemon.pl, by Ian
       7                 :            :  * Jackson <ijackson@gnu.ai.mit.edu>.  May be used and distributed
       8                 :            :  * freely for any purpose.  Changes by Christian Schwarz
       9                 :            :  * <schwarz@monet.m.isar.de>, to make output conform to the Debian
      10                 :            :  * Console Message Standard, also placed in public domain.  Minor
      11                 :            :  * changes by Klee Dienes <klee@debian.org>, also placed in the Public
      12                 :            :  * Domain.
      13                 :            :  *
      14                 :            :  * Changes by Ben Collins <bcollins@debian.org>, added --chuid, --background
      15                 :            :  * and --make-pidfile options, placed in public domain as well.
      16                 :            :  *
      17                 :            :  * Port to OpenBSD by Sontri Tomo Huynh <huynh.29@osu.edu>
      18                 :            :  *                 and Andreas Schuldei <andreas@schuldei.org>
      19                 :            :  *
      20                 :            :  * Changes by Ian Jackson: added --retry (and associated rearrangements).
      21                 :            :  */
      22                 :            : 
      23                 :            : #include <config.h>
      24                 :            : #include <compat.h>
      25                 :            : 
      26                 :            : #include <dpkg/macros.h>
      27                 :            : 
      28                 :            : #if defined(__linux__)
      29                 :            : #  define OS_Linux
      30                 :            : #elif defined(__GNU__)
      31                 :            : #  define OS_Hurd
      32                 :            : #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
      33                 :            : #  define OS_FreeBSD
      34                 :            : #elif defined(__NetBSD__)
      35                 :            : #  define OS_NetBSD
      36                 :            : #elif defined(__OpenBSD__)
      37                 :            : #  define OS_OpenBSD
      38                 :            : #elif defined(__DragonFly__)
      39                 :            : #  define OS_DragonFlyBSD
      40                 :            : #elif defined(__APPLE__) && defined(__MACH__)
      41                 :            : #  define OS_Darwin
      42                 :            : #elif defined(__sun)
      43                 :            : #  define OS_Solaris
      44                 :            : #elif defined(_AIX)
      45                 :            : #  define OS_AIX
      46                 :            : #elif defined(__hpux)
      47                 :            : #  define OS_HPUX
      48                 :            : #else
      49                 :            : #  error Unknown architecture - cannot build start-stop-daemon
      50                 :            : #endif
      51                 :            : 
      52                 :            : /* NetBSD needs this to expose struct proc. */
      53                 :            : #define _KMEMUSER 1
      54                 :            : 
      55                 :            : #ifdef HAVE_SYS_PARAM_H
      56                 :            : #include <sys/param.h>
      57                 :            : #endif
      58                 :            : #ifdef HAVE_SYS_SYSCALL_H
      59                 :            : #include <sys/syscall.h>
      60                 :            : #endif
      61                 :            : #ifdef HAVE_SYS_SYSCTL_H
      62                 :            : #include <sys/sysctl.h>
      63                 :            : #endif
      64                 :            : #ifdef HAVE_SYS_PROCFS_H
      65                 :            : #include <sys/procfs.h>
      66                 :            : #endif
      67                 :            : #ifdef HAVE_SYS_PROC_H
      68                 :            : #include <sys/proc.h>
      69                 :            : #endif
      70                 :            : #ifdef HAVE_SYS_USER_H
      71                 :            : #include <sys/user.h>
      72                 :            : #endif
      73                 :            : #ifdef HAVE_SYS_PSTAT_H
      74                 :            : #include <sys/pstat.h>
      75                 :            : #endif
      76                 :            : #include <sys/types.h>
      77                 :            : #include <sys/time.h>
      78                 :            : #include <sys/stat.h>
      79                 :            : #include <sys/wait.h>
      80                 :            : #include <sys/select.h>
      81                 :            : #include <sys/ioctl.h>
      82                 :            : #include <sys/socket.h>
      83                 :            : #include <sys/un.h>
      84                 :            : 
      85                 :            : #include <errno.h>
      86                 :            : #include <limits.h>
      87                 :            : #include <time.h>
      88                 :            : #include <fcntl.h>
      89                 :            : #include <dirent.h>
      90                 :            : #include <ctype.h>
      91                 :            : #include <string.h>
      92                 :            : #include <pwd.h>
      93                 :            : #include <grp.h>
      94                 :            : #include <signal.h>
      95                 :            : #include <termios.h>
      96                 :            : #include <unistd.h>
      97                 :            : #ifdef HAVE_STDDEF_H
      98                 :            : #include <stddef.h>
      99                 :            : #endif
     100                 :            : #include <stdbool.h>
     101                 :            : #include <stdarg.h>
     102                 :            : #include <stdlib.h>
     103                 :            : #include <stdio.h>
     104                 :            : #include <getopt.h>
     105                 :            : #ifdef HAVE_ERROR_H
     106                 :            : #include <error.h>
     107                 :            : #endif
     108                 :            : #ifdef HAVE_ERR_H
     109                 :            : #include <err.h>
     110                 :            : #endif
     111                 :            : 
     112                 :            : #if defined(OS_Hurd)
     113                 :            : #include <hurd.h>
     114                 :            : #include <ps.h>
     115                 :            : #endif
     116                 :            : 
     117                 :            : #if defined(OS_Darwin)
     118                 :            : #include <libproc.h>
     119                 :            : #endif
     120                 :            : 
     121                 :            : #ifdef HAVE_KVM_H
     122                 :            : #include <kvm.h>
     123                 :            : #if defined(OS_FreeBSD)
     124                 :            : #define KVM_MEMFILE "/dev/null"
     125                 :            : #else
     126                 :            : #define KVM_MEMFILE NULL
     127                 :            : #endif
     128                 :            : #endif
     129                 :            : 
     130                 :            : #if defined(_POSIX_PRIORITY_SCHEDULING) && _POSIX_PRIORITY_SCHEDULING > 0
     131                 :            : #include <sched.h>
     132                 :            : #else
     133                 :            : #define SCHED_OTHER -1
     134                 :            : #define SCHED_FIFO -1
     135                 :            : #define SCHED_RR -1
     136                 :            : #endif
     137                 :            : 
     138                 :            : /* At least macOS and AIX do not define this. */
     139                 :            : #ifndef SOCK_NONBLOCK
     140                 :            : #define SOCK_NONBLOCK 0
     141                 :            : #endif
     142                 :            : 
     143                 :            : #if defined(OS_Linux)
     144                 :            : /* This comes from TASK_COMM_LEN defined in Linux' include/linux/sched.h. */
     145                 :            : #define PROCESS_NAME_SIZE 15
     146                 :            : #elif defined(OS_Solaris)
     147                 :            : #define PROCESS_NAME_SIZE 15
     148                 :            : #elif defined(OS_Darwin)
     149                 :            : #define PROCESS_NAME_SIZE 16
     150                 :            : #elif defined(OS_AIX)
     151                 :            : /* This comes from PRFNSZ defined in AIX's <sys/procfs.h>. */
     152                 :            : #define PROCESS_NAME_SIZE 16
     153                 :            : #elif defined(OS_NetBSD)
     154                 :            : #define PROCESS_NAME_SIZE 16
     155                 :            : #elif defined(OS_OpenBSD)
     156                 :            : #define PROCESS_NAME_SIZE 16
     157                 :            : #elif defined(OS_FreeBSD)
     158                 :            : #define PROCESS_NAME_SIZE 19
     159                 :            : #elif defined(OS_DragonFlyBSD)
     160                 :            : /* On DragonFlyBSD MAXCOMLEN expands to 16. */
     161                 :            : #define PROCESS_NAME_SIZE MAXCOMLEN
     162                 :            : #endif
     163                 :            : 
     164                 :            : #if defined(SYS_ioprio_set) && defined(linux)
     165                 :            : #define HAVE_IOPRIO_SET
     166                 :            : #endif
     167                 :            : 
     168                 :            : #define IOPRIO_CLASS_SHIFT 13
     169                 :            : #define IOPRIO_PRIO_VALUE(class, prio) (((class) << IOPRIO_CLASS_SHIFT) | (prio))
     170                 :            : #define IO_SCHED_PRIO_MIN 0
     171                 :            : #define IO_SCHED_PRIO_MAX 7
     172                 :            : 
     173                 :            : enum {
     174                 :            :         IOPRIO_WHO_PROCESS = 1,
     175                 :            :         IOPRIO_WHO_PGRP,
     176                 :            :         IOPRIO_WHO_USER,
     177                 :            : };
     178                 :            : 
     179                 :            : enum {
     180                 :            :         IOPRIO_CLASS_NONE,
     181                 :            :         IOPRIO_CLASS_RT,
     182                 :            :         IOPRIO_CLASS_BE,
     183                 :            :         IOPRIO_CLASS_IDLE,
     184                 :            : };
     185                 :            : 
     186                 :            : enum action_code {
     187                 :            :         ACTION_NONE,
     188                 :            :         ACTION_START,
     189                 :            :         ACTION_STOP,
     190                 :            :         ACTION_STATUS,
     191                 :            : };
     192                 :            : 
     193                 :            : enum match_code {
     194                 :            :         MATCH_NONE      = 0,
     195                 :            :         MATCH_PID       = 1 << 0,
     196                 :            :         MATCH_PPID      = 1 << 1,
     197                 :            :         MATCH_PIDFILE   = 1 << 2,
     198                 :            :         MATCH_EXEC      = 1 << 3,
     199                 :            :         MATCH_NAME      = 1 << 4,
     200                 :            :         MATCH_USER      = 1 << 5,
     201                 :            : };
     202                 :            : 
     203                 :            : /* Time conversion constants. */
     204                 :            : enum {
     205                 :            :         NANOSEC_IN_SEC      = 1000000000L,
     206                 :            :         NANOSEC_IN_MILLISEC = 1000000L,
     207                 :            :         NANOSEC_IN_MICROSEC = 1000L,
     208                 :            : };
     209                 :            : 
     210                 :            : /* The minimum polling interval, 20ms. */
     211                 :            : static const long MIN_POLL_INTERVAL = 20L * NANOSEC_IN_MILLISEC;
     212                 :            : 
     213                 :            : static enum action_code action;
     214                 :            : static enum match_code match_mode;
     215                 :            : static bool testmode = false;
     216                 :            : static int quietmode = 0;
     217                 :            : static int exitnodo = 1;
     218                 :            : static bool background = false;
     219                 :            : static bool close_io = true;
     220                 :            : static const char *output_io;
     221                 :            : static bool notify_await = false;
     222                 :            : static int notify_timeout = 60;
     223                 :            : static char *notify_sockdir;
     224                 :            : static char *notify_socket;
     225                 :            : static bool mpidfile = false;
     226                 :            : static bool rpidfile = false;
     227                 :            : static int signal_nr = SIGTERM;
     228                 :            : static int user_id = -1;
     229                 :            : static int runas_uid = -1;
     230                 :            : static int runas_gid = -1;
     231                 :            : static const char *userspec = NULL;
     232                 :            : static char *changeuser = NULL;
     233                 :            : static const char *changegroup = NULL;
     234                 :            : static char *changeroot = NULL;
     235                 :            : static const char *changedir = "/";
     236                 :            : static const char *cmdname = NULL;
     237                 :            : static char *execname = NULL;
     238                 :            : static char *startas = NULL;
     239                 :            : static pid_t match_pid = -1;
     240                 :            : static pid_t match_ppid = -1;
     241                 :            : static const char *pidfile = NULL;
     242                 :            : static char *what_stop = NULL;
     243                 :            : static const char *progname = "";
     244                 :            : static int nicelevel = 0;
     245                 :            : static int umask_value = -1;
     246                 :            : 
     247                 :            : static struct stat exec_stat;
     248                 :            : #if defined(OS_Hurd)
     249                 :            : static struct proc_stat_list *procset = NULL;
     250                 :            : #endif
     251                 :            : 
     252                 :            : /* LSB Init Script process status exit codes. */
     253                 :            : enum status_code {
     254                 :            :         STATUS_OK = 0,
     255                 :            :         STATUS_DEAD_PIDFILE = 1,
     256                 :            :         STATUS_DEAD_LOCKFILE = 2,
     257                 :            :         STATUS_DEAD = 3,
     258                 :            :         STATUS_UNKNOWN = 4,
     259                 :            : };
     260                 :            : 
     261                 :            : struct pid_list {
     262                 :            :         struct pid_list *next;
     263                 :            :         pid_t pid;
     264                 :            : };
     265                 :            : 
     266                 :            : static struct pid_list *found = NULL;
     267                 :            : static struct pid_list *killed = NULL;
     268                 :            : 
     269                 :            : /* Resource scheduling policy. */
     270                 :            : struct res_schedule {
     271                 :            :         const char *policy_name;
     272                 :            :         int policy;
     273                 :            :         int priority;
     274                 :            : };
     275                 :            : 
     276                 :            : struct schedule_item {
     277                 :            :         enum {
     278                 :            :                 sched_timeout,
     279                 :            :                 sched_signal,
     280                 :            :                 sched_goto,
     281                 :            :                 /* Only seen within parse_schedule and callees. */
     282                 :            :                 sched_forever,
     283                 :            :         } type;
     284                 :            :         /* Seconds, signal no., or index into array. */
     285                 :            :         int value;
     286                 :            : };
     287                 :            : 
     288                 :            : static struct res_schedule *proc_sched = NULL;
     289                 :            : static struct res_schedule *io_sched = NULL;
     290                 :            : 
     291                 :            : static int schedule_length;
     292                 :            : static struct schedule_item *schedule = NULL;
     293                 :            : 
     294                 :            : 
     295                 :            : static void DPKG_ATTR_PRINTF(1)
     296                 :          0 : debug(const char *format, ...)
     297                 :            : {
     298                 :            :         va_list arglist;
     299                 :            : 
     300         [ #  # ]:          0 :         if (quietmode >= 0)
     301                 :          0 :                 return;
     302                 :            : 
     303                 :          0 :         va_start(arglist, format);
     304                 :          0 :         vprintf(format, arglist);
     305                 :          0 :         va_end(arglist);
     306                 :            : }
     307                 :            : 
     308                 :            : static void DPKG_ATTR_PRINTF(1)
     309                 :          0 : info(const char *format, ...)
     310                 :            : {
     311                 :            :         va_list arglist;
     312                 :            : 
     313         [ #  # ]:          0 :         if (quietmode > 0)
     314                 :          0 :                 return;
     315                 :            : 
     316                 :          0 :         va_start(arglist, format);
     317                 :          0 :         vprintf(format, arglist);
     318                 :          0 :         va_end(arglist);
     319                 :            : }
     320                 :            : 
     321                 :            : static void DPKG_ATTR_PRINTF(1)
     322                 :          0 : warning(const char *format, ...)
     323                 :            : {
     324                 :            :         va_list arglist;
     325                 :            : 
     326                 :          0 :         fprintf(stderr, "%s: warning: ", progname);
     327                 :          0 :         va_start(arglist, format);
     328                 :          0 :         vfprintf(stderr, format, arglist);
     329                 :          0 :         va_end(arglist);
     330                 :          0 : }
     331                 :            : 
     332                 :            : static void DPKG_ATTR_NORET DPKG_ATTR_VPRINTF(2)
     333                 :          0 : fatalv(int errno_fatal, const char *format, va_list args)
     334                 :            : {
     335                 :            :         va_list args_copy;
     336                 :            : 
     337                 :          0 :         fprintf(stderr, "%s: ", progname);
     338                 :          0 :         va_copy(args_copy, args);
     339                 :          0 :         vfprintf(stderr, format, args_copy);
     340                 :          0 :         va_end(args_copy);
     341         [ #  # ]:          0 :         if (errno_fatal)
     342                 :          0 :                 fprintf(stderr, " (%s)\n", strerror(errno_fatal));
     343                 :            :         else
     344                 :          0 :                 fprintf(stderr, "\n");
     345                 :            : 
     346         [ #  # ]:          0 :         if (action == ACTION_STATUS)
     347                 :          0 :                 exit(STATUS_UNKNOWN);
     348                 :            :         else
     349                 :          0 :                 exit(2);
     350                 :            : }
     351                 :            : 
     352                 :            : static void DPKG_ATTR_NORET DPKG_ATTR_PRINTF(1)
     353                 :          0 : fatal(const char *format, ...)
     354                 :            : {
     355                 :            :         va_list args;
     356                 :            : 
     357                 :          0 :         va_start(args, format);
     358                 :          0 :         fatalv(0, format, args);
     359                 :            : }
     360                 :            : 
     361                 :            : static void DPKG_ATTR_NORET DPKG_ATTR_PRINTF(1)
     362                 :          0 : fatale(const char *format, ...)
     363                 :            : {
     364                 :            :         va_list args;
     365                 :            : 
     366                 :          0 :         va_start(args, format);
     367                 :          0 :         fatalv(errno, format, args);
     368                 :            : }
     369                 :            : 
     370                 :            : #define BUG(...) bug(__FILE__, __LINE__, __func__, __VA_ARGS__)
     371                 :            : 
     372                 :            : static void DPKG_ATTR_NORET DPKG_ATTR_PRINTF(4)
     373                 :          0 : bug(const char *file, int line, const char *func, const char *format, ...)
     374                 :            : {
     375                 :            :         va_list arglist;
     376                 :            : 
     377                 :          0 :         fprintf(stderr, "%s:%s:%d:%s: internal error: ",
     378                 :            :                 progname, file, line, func);
     379                 :          0 :         va_start(arglist, format);
     380                 :          0 :         vfprintf(stderr, format, arglist);
     381                 :          0 :         va_end(arglist);
     382                 :            : 
     383         [ #  # ]:          0 :         if (action == ACTION_STATUS)
     384                 :          0 :                 exit(STATUS_UNKNOWN);
     385                 :            :         else
     386                 :          0 :                 exit(3);
     387                 :            : }
     388                 :            : 
     389                 :            : static void *
     390                 :          0 : xmalloc(int size)
     391                 :            : {
     392                 :            :         void *ptr;
     393                 :            : 
     394                 :          0 :         ptr = malloc(size);
     395         [ #  # ]:          0 :         if (ptr)
     396                 :          0 :                 return ptr;
     397                 :          0 :         fatale("malloc(%d) failed", size);
     398                 :            : }
     399                 :            : 
     400                 :            : static char *
     401                 :          0 : xstrndup(const char *str, size_t n)
     402                 :            : {
     403                 :            :         char *new_str;
     404                 :            : 
     405                 :          0 :         new_str = strndup(str, n);
     406         [ #  # ]:          0 :         if (new_str)
     407                 :          0 :                 return new_str;
     408                 :          0 :         fatale("strndup(%s, %zu) failed", str, n);
     409                 :            : }
     410                 :            : 
     411                 :            : static void
     412                 :          0 : timespec_gettime(struct timespec *ts)
     413                 :            : {
     414                 :            : #if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && \
     415                 :            :     defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK > 0
     416                 :            :         if (clock_gettime(CLOCK_MONOTONIC, ts) < 0)
     417                 :            :                 fatale("clock_gettime failed");
     418                 :            : #else
     419                 :            :         struct timeval tv;
     420                 :            : 
     421         [ #  # ]:          0 :         if (gettimeofday(&tv, NULL) != 0)
     422                 :          0 :                 fatale("gettimeofday failed");
     423                 :            : 
     424                 :          0 :         ts->tv_sec = tv.tv_sec;
     425                 :          0 :         ts->tv_nsec = tv.tv_usec * NANOSEC_IN_MICROSEC;
     426                 :            : #endif
     427                 :          0 : }
     428                 :            : 
     429                 :            : #define timespec_cmp(a, b, OP) \
     430                 :            :         (((a)->tv_sec == (b)->tv_sec) ? \
     431                 :            :          ((a)->tv_nsec OP (b)->tv_nsec) : \
     432                 :            :          ((a)->tv_sec OP (b)->tv_sec))
     433                 :            : 
     434                 :            : static void
     435                 :          0 : timespec_sub(struct timespec *a, struct timespec *b, struct timespec *res)
     436                 :            : {
     437                 :          0 :         res->tv_sec = a->tv_sec - b->tv_sec;
     438                 :          0 :         res->tv_nsec = a->tv_nsec - b->tv_nsec;
     439         [ #  # ]:          0 :         if (res->tv_nsec < 0) {
     440                 :          0 :                 res->tv_sec--;
     441                 :          0 :                 res->tv_nsec += NANOSEC_IN_SEC;
     442                 :            :         }
     443                 :          0 : }
     444                 :            : 
     445                 :            : static void
     446                 :          0 : timespec_mul(struct timespec *a, int b)
     447                 :            : {
     448                 :          0 :         long nsec = a->tv_nsec * b;
     449                 :            : 
     450                 :          0 :         a->tv_sec *= b;
     451                 :          0 :         a->tv_sec += nsec / NANOSEC_IN_SEC;
     452                 :          0 :         a->tv_nsec = nsec % NANOSEC_IN_SEC;
     453                 :          0 : }
     454                 :            : 
     455                 :            : static char *
     456                 :          0 : newpath(const char *dirname, const char *filename)
     457                 :            : {
     458                 :            :         char *path;
     459                 :            :         size_t path_len;
     460                 :            : 
     461                 :          0 :         path_len = strlen(dirname) + 1 + strlen(filename) + 1;
     462                 :          0 :         path = xmalloc(path_len);
     463                 :          0 :         snprintf(path, path_len, "%s/%s", dirname, filename);
     464                 :            : 
     465                 :          0 :         return path;
     466                 :            : }
     467                 :            : 
     468                 :            : static int
     469                 :          0 : parse_unsigned(const char *string, int base, int *value_r)
     470                 :            : {
     471                 :            :         long value;
     472                 :            :         char *endptr;
     473                 :            : 
     474                 :          0 :         errno = 0;
     475         [ #  # ]:          0 :         if (!string[0])
     476                 :          0 :                 return -1;
     477                 :            : 
     478                 :          0 :         value = strtol(string, &endptr, base);
     479   [ #  #  #  #  :          0 :         if (string == endptr || *endptr != '\0' || errno != 0)
                   #  # ]
     480                 :          0 :                 return -1;
     481   [ #  #  #  # ]:          0 :         if (value < 0 || value > INT_MAX)
     482                 :          0 :                 return -1;
     483                 :            : 
     484                 :          0 :         *value_r = value;
     485                 :          0 :         return 0;
     486                 :            : }
     487                 :            : 
     488                 :            : static long
     489                 :          0 : get_open_fd_max(void)
     490                 :            : {
     491                 :            : #ifdef HAVE_GETDTABLESIZE
     492                 :          0 :         return getdtablesize();
     493                 :            : #else
     494                 :            :         return sysconf(_SC_OPEN_MAX);
     495                 :            : #endif
     496                 :            : }
     497                 :            : 
     498                 :            : #ifndef HAVE_SETSID
     499                 :            : static void
     500                 :            : detach_controlling_tty(void)
     501                 :            : {
     502                 :            : #ifdef HAVE_TIOCNOTTY
     503                 :            :         int tty_fd;
     504                 :            : 
     505                 :            :         tty_fd = open("/dev/tty", O_RDWR);
     506                 :            : 
     507                 :            :         /* The current process does not have a controlling tty. */
     508                 :            :         if (tty_fd < 0)
     509                 :            :                 return;
     510                 :            : 
     511                 :            :         if (ioctl(tty_fd, TIOCNOTTY, 0) != 0)
     512                 :            :                 fatale("unable to detach controlling tty");
     513                 :            : 
     514                 :            :         close(tty_fd);
     515                 :            : #endif
     516                 :            : }
     517                 :            : 
     518                 :            : static pid_t
     519                 :            : setsid(void)
     520                 :            : {
     521                 :            :         if (setpgid(0, 0) < 0)
     522                 :            :                 return -1:
     523                 :            : 
     524                 :            :         detach_controlling_tty();
     525                 :            : 
     526                 :            :         return 0;
     527                 :            : }
     528                 :            : #endif
     529                 :            : 
     530                 :            : static void
     531                 :          0 : wait_for_child(pid_t pid)
     532                 :            : {
     533                 :            :         pid_t child;
     534                 :            :         int status;
     535                 :            : 
     536                 :            :         do {
     537                 :          0 :                 child = waitpid(pid, &status, 0);
     538   [ #  #  #  # ]:          0 :         } while (child == -1 && errno == EINTR);
     539                 :            : 
     540         [ #  # ]:          0 :         if (child != pid)
     541                 :          0 :                 fatal("error waiting for child");
     542                 :            : 
     543         [ #  # ]:          0 :         if (WIFEXITED(status)) {
     544                 :          0 :                 int ret = WEXITSTATUS(status);
     545                 :            : 
     546         [ #  # ]:          0 :                 if (ret != 0)
     547                 :          0 :                         fatal("child returned error exit status %d", ret);
     548         [ #  # ]:          0 :         } else if (WIFSIGNALED(status)) {
     549                 :          0 :                 int signo = WTERMSIG(status);
     550                 :            : 
     551                 :          0 :                 fatal("child was killed by signal %d", signo);
     552                 :            :         } else {
     553                 :          0 :                 fatal("unexpected status %d waiting for child", status);
     554                 :            :         }
     555                 :          0 : }
     556                 :            : 
     557                 :            : static void
     558                 :          0 : cleanup_socket_dir(void)
     559                 :            : {
     560                 :          0 :         (void)unlink(notify_socket);
     561                 :          0 :         (void)rmdir(notify_sockdir);
     562                 :          0 : }
     563                 :            : 
     564                 :            : static char *
     565                 :          0 : setup_socket_name(const char *suffix)
     566                 :            : {
     567                 :            :         const char *basedir;
     568                 :            : 
     569   [ #  #  #  # ]:          0 :         if (getuid() == 0 && access(RUNSTATEDIR, F_OK) == 0) {
     570                 :          0 :                 basedir = RUNSTATEDIR;
     571                 :            :         } else {
     572                 :          0 :                 basedir = getenv("TMPDIR");
     573         [ #  # ]:          0 :                 if (basedir == NULL)
     574                 :          0 :                         basedir = P_tmpdir;
     575                 :            :         }
     576                 :            : 
     577         [ #  # ]:          0 :         if (asprintf(&notify_sockdir, "%s/%s.XXXXXX", basedir, suffix) < 0)
     578                 :          0 :                 fatale("cannot allocate socket directory name");
     579                 :            : 
     580         [ #  # ]:          0 :         if (mkdtemp(notify_sockdir) == NULL)
     581                 :          0 :                 fatale("cannot create socket directory %s", notify_sockdir);
     582                 :            : 
     583                 :          0 :         atexit(cleanup_socket_dir);
     584                 :            : 
     585         [ #  # ]:          0 :         if (chown(notify_sockdir, runas_uid, runas_gid))
     586                 :          0 :                 fatale("cannot change socket directory ownership");
     587                 :            : 
     588         [ #  # ]:          0 :         if (asprintf(&notify_socket, "%s/notify", notify_sockdir) < 0)
     589                 :          0 :                 fatale("cannot allocate socket name");
     590                 :            : 
     591                 :          0 :         setenv("NOTIFY_SOCKET", notify_socket, 1);
     592                 :            : 
     593                 :          0 :         return notify_socket;
     594                 :            : }
     595                 :            : 
     596                 :            : static void
     597                 :          0 : set_socket_passcred(int fd)
     598                 :            : {
     599                 :            : #ifdef SO_PASSCRED
     600                 :            :         static const int enable = 1;
     601                 :            : 
     602                 :          0 :         (void)setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable));
     603                 :            : #endif
     604                 :          0 : }
     605                 :            : 
     606                 :            : static int
     607                 :          0 : create_notify_socket(void)
     608                 :            : {
     609                 :            :         const char *sockname;
     610                 :            :         struct sockaddr_un su;
     611                 :            :         int fd, rc, flags;
     612                 :            : 
     613                 :            :         /* Create notification socket. */
     614                 :          0 :         fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0);
     615         [ #  # ]:          0 :         if (fd < 0)
     616                 :          0 :                 fatale("cannot create notification socket");
     617                 :            : 
     618                 :            :         /* We could set SOCK_CLOEXEC instead, but then we would need to
     619                 :            :          * check whether the socket call failed, try and then do this anyway,
     620                 :            :          * when we have no threading problems to worry about. */
     621                 :          0 :         flags = fcntl(fd, F_GETFD);
     622         [ #  # ]:          0 :         if (flags < 0)
     623                 :          0 :                 fatale("cannot read fd flags for notification socket");
     624         [ #  # ]:          0 :         if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0)
     625                 :          0 :                 fatale("cannot set close-on-exec flag for notification socket");
     626                 :            : 
     627                 :          0 :         sockname = setup_socket_name(".s-s-d-notify");
     628                 :            : 
     629                 :            :         /* Bind to a socket in a temporary directory, selected based on
     630                 :            :          * the platform. */
     631                 :          0 :         memset(&su, 0, sizeof(su));
     632                 :          0 :         su.sun_family = AF_UNIX;
     633                 :          0 :         strncpy(su.sun_path, sockname, sizeof(su.sun_path) - 1);
     634                 :            : 
     635                 :          0 :         rc = bind(fd, &su, sizeof(su));
     636         [ #  # ]:          0 :         if (rc < 0)
     637                 :          0 :                 fatale("cannot bind to notification socket");
     638                 :            : 
     639                 :          0 :         rc = chmod(su.sun_path, 0660);
     640         [ #  # ]:          0 :         if (rc < 0)
     641                 :          0 :                 fatale("cannot change notification socket permissions");
     642                 :            : 
     643                 :          0 :         rc = chown(su.sun_path, runas_uid, runas_gid);
     644         [ #  # ]:          0 :         if (rc < 0)
     645                 :          0 :                 fatale("cannot change notification socket ownership");
     646                 :            : 
     647                 :            :         /* XXX: Verify we are talking to an expected child? Although it is not
     648                 :            :          * clear whether this is feasible given the knowledge we have got. */
     649                 :          0 :         set_socket_passcred(fd);
     650                 :            : 
     651                 :          0 :         return fd;
     652                 :            : }
     653                 :            : 
     654                 :            : static void
     655                 :          0 : wait_for_notify(int fd)
     656                 :            : {
     657                 :            :         struct timespec startat, now, elapsed, timeout, timeout_orig;
     658                 :            :         fd_set fdrs;
     659                 :            :         int rc;
     660                 :            : 
     661                 :          0 :         timeout.tv_sec = notify_timeout;
     662                 :          0 :         timeout.tv_nsec = 0;
     663                 :          0 :         timeout_orig = timeout;
     664                 :            : 
     665                 :          0 :         timespec_gettime(&startat);
     666                 :            : 
     667   [ #  #  #  # ]:          0 :         while (timeout.tv_sec >= 0 && timeout.tv_nsec >= 0) {
     668         [ #  # ]:          0 :                 FD_ZERO(&fdrs);
     669                 :          0 :                 FD_SET(fd, &fdrs);
     670                 :            : 
     671                 :            :                 /* Wait for input. */
     672                 :          0 :                 debug("Waiting for notifications... (timeout %lusec %lunsec)\n",
     673                 :            :                       timeout.tv_sec, timeout.tv_nsec);
     674                 :          0 :                 rc = pselect(fd + 1, &fdrs, NULL, NULL, &timeout, NULL);
     675                 :            : 
     676                 :            :                 /* Catch non-restartable errors, that is, not signals nor
     677                 :            :                  * kernel out of resources. */
     678   [ #  #  #  #  :          0 :                 if (rc < 0 && (errno != EINTR && errno != EAGAIN))
                   #  # ]
     679                 :          0 :                         fatale("cannot monitor notification socket for activity");
     680                 :            : 
     681                 :            :                 /* Timed-out. */
     682         [ #  # ]:          0 :                 if (rc == 0)
     683                 :          0 :                         fatal("timed out waiting for a notification");
     684                 :            : 
     685                 :            :                 /* Update the timeout, as should not rely on pselect() having
     686                 :            :                  * done that for us, which is an unportable assumption. */
     687                 :          0 :                 timespec_gettime(&now);
     688                 :          0 :                 timespec_sub(&now, &startat, &elapsed);
     689                 :          0 :                 timespec_sub(&timeout_orig, &elapsed, &timeout);
     690                 :            : 
     691                 :            :                 /* Restartable error, a signal or kernel out of resources. */
     692         [ #  # ]:          0 :                 if (rc < 0)
     693                 :          0 :                         continue;
     694                 :            : 
     695                 :            :                 /* Parse it and check for a supported notification message,
     696                 :            :                  * once we get a READY=1, we exit. */
     697                 :          0 :                 for (;;) {
     698                 :            :                         ssize_t nrecv;
     699                 :            :                         char buf[4096];
     700                 :            :                         char *line, *line_next;
     701                 :            : 
     702                 :          0 :                         nrecv = recv(fd, buf, sizeof(buf), 0);
     703   [ #  #  #  #  :          0 :                         if (nrecv < 0 && (errno != EINTR && errno != EAGAIN))
                   #  # ]
     704                 :          0 :                                 fatale("cannot receive notification packet");
     705         [ #  # ]:          0 :                         if (nrecv < 0)
     706                 :          0 :                                 break;
     707                 :            : 
     708                 :          0 :                         buf[nrecv] = '\0';
     709                 :            : 
     710         [ #  # ]:          0 :                         for (line = buf; *line; line = line_next) {
     711                 :          0 :                                 line_next = strchrnul(line, '\n');
     712         [ #  # ]:          0 :                                 if (*line_next == '\n')
     713                 :          0 :                                         *line_next++ = '\0';
     714                 :            : 
     715                 :          0 :                                 debug("Child sent some notification...\n");
     716         [ #  # ]:          0 :                                 if (strncmp(line, "EXTEND_TIMEOUT_USEC=", 20) == 0) {
     717                 :          0 :                                         int extend_usec = 0;
     718                 :            : 
     719         [ #  # ]:          0 :                                         if (parse_unsigned(line + 20, 10, &extend_usec) != 0)
     720                 :          0 :                                                 fatale("cannot parse extended timeout notification %s", line);
     721                 :            : 
     722                 :            :                                         /* Reset the current timeout. */
     723                 :          0 :                                         timeout.tv_sec = extend_usec / 1000L;
     724                 :          0 :                                         timeout.tv_nsec = (extend_usec % 1000L) *
     725                 :            :                                                           NANOSEC_IN_MILLISEC;
     726                 :          0 :                                         timeout_orig = timeout;
     727                 :            : 
     728                 :          0 :                                         timespec_gettime(&startat);
     729         [ #  # ]:          0 :                                 } else if (strncmp(line, "ERRNO=", 6) == 0) {
     730                 :          0 :                                         int suberrno = 0;
     731                 :            : 
     732         [ #  # ]:          0 :                                         if (parse_unsigned(line + 6, 10, &suberrno) != 0)
     733                 :          0 :                                                 fatale("cannot parse errno notification %s", line);
     734                 :          0 :                                         errno = suberrno;
     735                 :          0 :                                         fatale("program failed to initialize");
     736         [ #  # ]:          0 :                                 } else if (strcmp(line, "READY=1") == 0) {
     737                 :          0 :                                         debug("-> Notification => ready for service.\n");
     738                 :          0 :                                         return;
     739                 :            :                                 } else {
     740                 :          0 :                                         debug("-> Notification line '%s' received\n", line);
     741                 :            :                                 }
     742                 :            :                         }
     743                 :            :                 }
     744                 :            :         }
     745                 :            : }
     746                 :            : 
     747                 :            : static void
     748                 :          0 : write_pidfile(const char *filename, pid_t pid)
     749                 :            : {
     750                 :            :         FILE *fp;
     751                 :            :         int fd;
     752                 :            : 
     753                 :          0 :         fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW, 0666);
     754         [ #  # ]:          0 :         if (fd < 0)
     755                 :          0 :                 fp = NULL;
     756                 :            :         else
     757                 :          0 :                 fp = fdopen(fd, "w");
     758                 :            : 
     759         [ #  # ]:          0 :         if (fp == NULL)
     760                 :          0 :                 fatale("unable to open pidfile '%s' for writing", filename);
     761                 :            : 
     762                 :          0 :         fprintf(fp, "%d\n", pid);
     763                 :            : 
     764         [ #  # ]:          0 :         if (fclose(fp))
     765                 :          0 :                 fatale("unable to close pidfile '%s'", filename);
     766                 :          0 : }
     767                 :            : 
     768                 :            : static void
     769                 :          0 : remove_pidfile(const char *filename)
     770                 :            : {
     771   [ #  #  #  # ]:          0 :         if (unlink(filename) < 0 && errno != ENOENT)
     772                 :          0 :                 fatale("cannot remove pidfile '%s'", filename);
     773                 :          0 : }
     774                 :            : 
     775                 :            : static void
     776                 :          0 : daemonize(void)
     777                 :            : {
     778                 :          0 :         int notify_fd = -1;
     779                 :            :         pid_t pid;
     780                 :            :         sigset_t mask;
     781                 :            :         sigset_t oldmask;
     782                 :            : 
     783                 :          0 :         debug("Detaching to start %s...\n", startas);
     784                 :            : 
     785                 :            :         /* Block SIGCHLD to allow waiting for the child process while it is
     786                 :            :          * performing actions, such as creating a pidfile. */
     787                 :          0 :         sigemptyset(&mask);
     788                 :          0 :         sigaddset(&mask, SIGCHLD);
     789         [ #  # ]:          0 :         if (sigprocmask(SIG_BLOCK, &mask, &oldmask) == -1)
     790                 :          0 :                 fatale("cannot block SIGCHLD");
     791                 :            : 
     792         [ #  # ]:          0 :         if (notify_await)
     793                 :          0 :                 notify_fd = create_notify_socket();
     794                 :            : 
     795                 :          0 :         pid = fork();
     796         [ #  # ]:          0 :         if (pid < 0)
     797                 :          0 :                 fatale("unable to do first fork");
     798         [ #  # ]:          0 :         else if (pid) { /* First Parent. */
     799                 :            :                 /* Wait for the second parent to exit, so that if we need to
     800                 :            :                  * perform any actions there, like creating a pidfile, we do
     801                 :            :                  * not suffer from race conditions on return. */
     802                 :          0 :                 wait_for_child(pid);
     803                 :            : 
     804         [ #  # ]:          0 :                 if (notify_await) {
     805                 :            :                         /* Wait for a readiness notification from the second
     806                 :            :                          * child, so that we can safely exit when the service
     807                 :            :                          * is up. */
     808                 :          0 :                         wait_for_notify(notify_fd);
     809                 :          0 :                         close(notify_fd);
     810                 :          0 :                         cleanup_socket_dir();
     811                 :            :                 }
     812                 :            : 
     813                 :          0 :                 _exit(0);
     814                 :            :         }
     815                 :            : 
     816                 :            :         /* Close the notification socket, even though it is close-on-exec. */
     817         [ #  # ]:          0 :         if (notify_await)
     818                 :          0 :                 close(notify_fd);
     819                 :            : 
     820                 :            :         /* Create a new session. */
     821         [ #  # ]:          0 :         if (setsid() < 0)
     822                 :          0 :                 fatale("cannot set session ID");
     823                 :            : 
     824                 :          0 :         pid = fork();
     825         [ #  # ]:          0 :         if (pid < 0)
     826                 :          0 :                 fatale("unable to do second fork");
     827         [ #  # ]:          0 :         else if (pid) { /* Second parent. */
     828                 :            :                 /* Set a default umask for dumb programs, which might get
     829                 :            :                  * overridden by the --umask option later on, so that we get
     830                 :            :                  * a defined umask when creating the pidfile. */
     831                 :          0 :                 umask(022);
     832                 :            : 
     833   [ #  #  #  # ]:          0 :                 if (mpidfile && pidfile != NULL)
     834                 :            :                         /* User wants _us_ to make the pidfile. */
     835                 :          0 :                         write_pidfile(pidfile, pid);
     836                 :            : 
     837                 :          0 :                 _exit(0);
     838                 :            :         }
     839                 :            : 
     840         [ #  # ]:          0 :         if (sigprocmask(SIG_SETMASK, &oldmask, NULL) == -1)
     841                 :          0 :                 fatale("cannot restore signal mask");
     842                 :            : 
     843                 :          0 :         debug("Detaching complete...\n");
     844                 :          0 : }
     845                 :            : 
     846                 :            : static void
     847                 :          0 : pid_list_push(struct pid_list **list, pid_t pid)
     848                 :            : {
     849                 :            :         struct pid_list *p;
     850                 :            : 
     851                 :          0 :         p = xmalloc(sizeof(*p));
     852                 :          0 :         p->next = *list;
     853                 :          0 :         p->pid = pid;
     854                 :          0 :         *list = p;
     855                 :          0 : }
     856                 :            : 
     857                 :            : static void
     858                 :          0 : pid_list_free(struct pid_list **list)
     859                 :            : {
     860                 :            :         struct pid_list *here, *next;
     861                 :            : 
     862         [ #  # ]:          0 :         for (here = *list; here != NULL; here = next) {
     863                 :          0 :                 next = here->next;
     864                 :          0 :                 free(here);
     865                 :            :         }
     866                 :            : 
     867                 :          0 :         *list = NULL;
     868                 :          0 : }
     869                 :            : 
     870                 :            : static void
     871                 :          0 : usage(void)
     872                 :            : {
     873                 :          0 :         printf(
     874                 :            : "Usage: start-stop-daemon [<option>...] <command>\n"
     875                 :            : "\n");
     876                 :            : 
     877                 :          0 :         printf(
     878                 :            : "Commands:\n"
     879                 :            : "  -S, --start -- <argument>...  start a program and pass <arguments> to it\n"
     880                 :            : "  -K, --stop                    stop a program\n"
     881                 :            : "  -T, --status                  get the program status\n"
     882                 :            : "  -H, --help                    print help information\n"
     883                 :            : "  -V, --version                 print version\n"
     884                 :            : "\n");
     885                 :            : 
     886                 :          0 :         printf(
     887                 :            : "Matching options (at least one is required):\n"
     888                 :            : "      --pid <pid>               pid to check\n"
     889                 :            : "      --ppid <ppid>             parent pid to check\n"
     890                 :            : "  -p, --pidfile <pid-file>      pid file to check\n"
     891                 :            : "  -x, --exec <executable>       program to start/check if it is running\n"
     892                 :            : "  -n, --name <process-name>     process name to check\n"
     893                 :            : "  -u, --user <username|uid>     process owner to check\n"
     894                 :            : "\n");
     895                 :            : 
     896                 :          0 :         printf(
     897                 :            : "Options:\n"
     898                 :            : "  -g, --group <group|gid>       run process as this group\n"
     899                 :            : "  -c, --chuid <name|uid[:group|gid]>\n"
     900                 :            : "                                change to this user/group before starting\n"
     901                 :            : "                                  process\n"
     902                 :            : "  -s, --signal <signal>         signal to send (default TERM)\n"
     903                 :            : "  -a, --startas <pathname>      program to start (default is <executable>)\n"
     904                 :            : "  -r, --chroot <directory>      chroot to <directory> before starting\n"
     905                 :            : "  -d, --chdir <directory>       change to <directory> (default is /)\n"
     906                 :            : "  -N, --nicelevel <incr>        add incr to the process' nice level\n"
     907                 :            : "  -P, --procsched <policy[:prio]>\n"
     908                 :            : "                                use <policy> with <prio> for the kernel\n"
     909                 :            : "                                  process scheduler (default prio is 0)\n"
     910                 :            : "  -I, --iosched <class[:prio]>  use <class> with <prio> to set the IO\n"
     911                 :            : "                                  scheduler (default prio is 4)\n"
     912                 :            : "  -k, --umask <mask>            change the umask to <mask> before starting\n"
     913                 :            : "  -b, --background              force the process to detach\n"
     914                 :            : "      --notify-await            wait for a readiness notification\n"
     915                 :            : "      --notify-timeout <int>    timeout after <int> seconds of notify wait\n"
     916                 :            : "  -C, --no-close                do not close any file descriptor\n"
     917                 :            : "  -O, --output <filename>       send stdout and stderr to <filename>\n"
     918                 :            : "  -m, --make-pidfile            create the pidfile before starting\n"
     919                 :            : "      --remove-pidfile          delete the pidfile after stopping\n"
     920                 :            : "  -R, --retry <schedule>        check whether processes die, and retry\n"
     921                 :            : "  -t, --test                    test mode, don't do anything\n"
     922                 :            : "  -o, --oknodo                  exit status 0 (not 1) if nothing done\n"
     923                 :            : "  -q, --quiet                   be more quiet\n"
     924                 :            : "  -v, --verbose                 be more verbose\n"
     925                 :            : "\n");
     926                 :            : 
     927                 :          0 :         printf(
     928                 :            : "Retry <schedule> is <item>|/<item>/... where <item> is one of\n"
     929                 :            : " -<signal-num>|[-]<signal-name>  send that signal\n"
     930                 :            : " <timeout>                       wait that many seconds\n"
     931                 :            : " forever                         repeat remainder forever\n"
     932                 :            : "or <schedule> may be just <timeout>, meaning <signal>/<timeout>/KILL/<timeout>\n"
     933                 :            : "\n");
     934                 :            : 
     935                 :          0 :         printf(
     936                 :            : "The process scheduler <policy> can be one of:\n"
     937                 :            : "  other, fifo or rr\n"
     938                 :            : "\n");
     939                 :            : 
     940                 :          0 :         printf(
     941                 :            : "The IO scheduler <class> can be one of:\n"
     942                 :            : "  real-time, best-effort or idle\n"
     943                 :            : "\n");
     944                 :            : 
     945                 :          0 :         printf(
     946                 :            : "Exit status:\n"
     947                 :            : "  0 = done\n"
     948                 :            : "  1 = nothing done (=> 0 if --oknodo)\n"
     949                 :            : "  2 = with --retry, processes would not die\n"
     950                 :            : "  3 = trouble\n"
     951                 :            : "Exit status with --status:\n"
     952                 :            : "  0 = program is running\n"
     953                 :            : "  1 = program is not running and the pid file exists\n"
     954                 :            : "  3 = program is not running\n"
     955                 :            : "  4 = unable to determine status\n");
     956                 :          0 : }
     957                 :            : 
     958                 :            : static void
     959                 :          0 : do_version(void)
     960                 :            : {
     961                 :          0 :         printf("start-stop-daemon %s for Debian\n\n", VERSION);
     962                 :            : 
     963                 :          0 :         printf("Written by Marek Michalkiewicz, public domain.\n");
     964                 :          0 : }
     965                 :            : 
     966                 :            : static void DPKG_ATTR_NORET
     967                 :          0 : badusage(const char *msg)
     968                 :            : {
     969         [ #  # ]:          0 :         if (msg)
     970                 :          0 :                 fprintf(stderr, "%s: %s\n", progname, msg);
     971                 :          0 :         fprintf(stderr, "Try '%s --help' for more information.\n", progname);
     972                 :            : 
     973         [ #  # ]:          0 :         if (action == ACTION_STATUS)
     974                 :          0 :                 exit(STATUS_UNKNOWN);
     975                 :            :         else
     976                 :          0 :                 exit(3);
     977                 :            : }
     978                 :            : 
     979                 :            : struct sigpair {
     980                 :            :         const char *name;
     981                 :            :         int signal;
     982                 :            : };
     983                 :            : 
     984                 :            : static const struct sigpair siglist[] = {
     985                 :            :         { "ABRT",     SIGABRT },
     986                 :            :         { "ALRM",     SIGALRM },
     987                 :            :         { "FPE",      SIGFPE  },
     988                 :            :         { "HUP",      SIGHUP  },
     989                 :            :         { "ILL",      SIGILL  },
     990                 :            :         { "INT",      SIGINT  },
     991                 :            :         { "KILL",     SIGKILL },
     992                 :            :         { "PIPE",     SIGPIPE },
     993                 :            :         { "QUIT",     SIGQUIT },
     994                 :            :         { "SEGV",     SIGSEGV },
     995                 :            :         { "TERM",     SIGTERM },
     996                 :            :         { "USR1",     SIGUSR1 },
     997                 :            :         { "USR2",     SIGUSR2 },
     998                 :            :         { "CHLD",     SIGCHLD },
     999                 :            :         { "CONT",     SIGCONT },
    1000                 :            :         { "STOP",     SIGSTOP },
    1001                 :            :         { "TSTP",     SIGTSTP },
    1002                 :            :         { "TTIN",     SIGTTIN },
    1003                 :            :         { "TTOU",     SIGTTOU }
    1004                 :            : };
    1005                 :            : 
    1006                 :            : static int
    1007                 :          0 : parse_pid(const char *pid_str, int *pid_num)
    1008                 :            : {
    1009         [ #  # ]:          0 :         if (parse_unsigned(pid_str, 10, pid_num) != 0)
    1010                 :          0 :                 return -1;
    1011         [ #  # ]:          0 :         if (*pid_num == 0)
    1012                 :          0 :                 return -1;
    1013                 :            : 
    1014                 :          0 :         return 0;
    1015                 :            : }
    1016                 :            : 
    1017                 :            : static int
    1018                 :          0 : parse_signal(const char *sig_str, int *sig_num)
    1019                 :            : {
    1020                 :            :         unsigned int i;
    1021                 :            : 
    1022         [ #  # ]:          0 :         if (parse_unsigned(sig_str, 10, sig_num) == 0)
    1023                 :          0 :                 return 0;
    1024                 :            : 
    1025         [ #  # ]:          0 :         for (i = 0; i < array_count(siglist); i++) {
    1026         [ #  # ]:          0 :                 if (strcmp(sig_str, siglist[i].name) == 0) {
    1027                 :          0 :                         *sig_num = siglist[i].signal;
    1028                 :          0 :                         return 0;
    1029                 :            :                 }
    1030                 :            :         }
    1031                 :          0 :         return -1;
    1032                 :            : }
    1033                 :            : 
    1034                 :            : static int
    1035                 :          0 : parse_umask(const char *string, int *value_r)
    1036                 :            : {
    1037                 :          0 :         return parse_unsigned(string, 0, value_r);
    1038                 :            : }
    1039                 :            : 
    1040                 :            : static void
    1041                 :          0 : validate_proc_schedule(void)
    1042                 :            : {
    1043                 :            : #if defined(_POSIX_PRIORITY_SCHEDULING) && _POSIX_PRIORITY_SCHEDULING > 0
    1044                 :            :         int prio_min, prio_max;
    1045                 :            : 
    1046                 :          0 :         prio_min = sched_get_priority_min(proc_sched->policy);
    1047                 :          0 :         prio_max = sched_get_priority_max(proc_sched->policy);
    1048                 :            : 
    1049         [ #  # ]:          0 :         if (proc_sched->priority < prio_min)
    1050                 :          0 :                 badusage("process scheduler priority less than min");
    1051         [ #  # ]:          0 :         if (proc_sched->priority > prio_max)
    1052                 :          0 :                 badusage("process scheduler priority greater than max");
    1053                 :            : #endif
    1054                 :          0 : }
    1055                 :            : 
    1056                 :            : static void
    1057                 :          0 : parse_proc_schedule(const char *string)
    1058                 :            : {
    1059                 :            :         char *policy_str;
    1060                 :            :         size_t policy_len;
    1061                 :          0 :         int prio = 0;
    1062                 :            : 
    1063                 :          0 :         policy_len = strcspn(string, ":");
    1064                 :          0 :         policy_str = xstrndup(string, policy_len);
    1065                 :            : 
    1066   [ #  #  #  # ]:          0 :         if (string[policy_len] == ':' &&
    1067                 :          0 :             parse_unsigned(string + policy_len + 1, 10, &prio) != 0)
    1068                 :          0 :                 fatale("invalid process scheduler priority");
    1069                 :            : 
    1070                 :          0 :         proc_sched = xmalloc(sizeof(*proc_sched));
    1071                 :          0 :         proc_sched->policy_name = policy_str;
    1072                 :            : 
    1073         [ #  # ]:          0 :         if (strcmp(policy_str, "other") == 0) {
    1074                 :          0 :                 proc_sched->policy = SCHED_OTHER;
    1075                 :          0 :                 proc_sched->priority = 0;
    1076         [ #  # ]:          0 :         } else if (strcmp(policy_str, "fifo") == 0) {
    1077                 :          0 :                 proc_sched->policy = SCHED_FIFO;
    1078                 :          0 :                 proc_sched->priority = prio;
    1079         [ #  # ]:          0 :         } else if (strcmp(policy_str, "rr") == 0) {
    1080                 :          0 :                 proc_sched->policy = SCHED_RR;
    1081                 :          0 :                 proc_sched->priority = prio;
    1082                 :            :         } else
    1083                 :          0 :                 badusage("invalid process scheduler policy");
    1084                 :            : 
    1085                 :          0 :         validate_proc_schedule();
    1086                 :          0 : }
    1087                 :            : 
    1088                 :            : static void
    1089                 :          0 : parse_io_schedule(const char *string)
    1090                 :            : {
    1091                 :            :         char *class_str;
    1092                 :            :         size_t class_len;
    1093                 :          0 :         int prio = 4;
    1094                 :            : 
    1095                 :          0 :         class_len = strcspn(string, ":");
    1096                 :          0 :         class_str = xstrndup(string, class_len);
    1097                 :            : 
    1098   [ #  #  #  # ]:          0 :         if (string[class_len] == ':' &&
    1099                 :          0 :             parse_unsigned(string + class_len + 1, 10, &prio) != 0)
    1100                 :          0 :                 fatale("invalid IO scheduler priority");
    1101                 :            : 
    1102                 :          0 :         io_sched = xmalloc(sizeof(*io_sched));
    1103                 :          0 :         io_sched->policy_name = class_str;
    1104                 :            : 
    1105         [ #  # ]:          0 :         if (strcmp(class_str, "real-time") == 0) {
    1106                 :          0 :                 io_sched->policy = IOPRIO_CLASS_RT;
    1107                 :          0 :                 io_sched->priority = prio;
    1108         [ #  # ]:          0 :         } else if (strcmp(class_str, "best-effort") == 0) {
    1109                 :          0 :                 io_sched->policy = IOPRIO_CLASS_BE;
    1110                 :          0 :                 io_sched->priority = prio;
    1111         [ #  # ]:          0 :         } else if (strcmp(class_str, "idle") == 0) {
    1112                 :          0 :                 io_sched->policy = IOPRIO_CLASS_IDLE;
    1113                 :          0 :                 io_sched->priority = 7;
    1114                 :            :         } else
    1115                 :          0 :                 badusage("invalid IO scheduler policy");
    1116                 :            : 
    1117         [ #  # ]:          0 :         if (io_sched->priority < IO_SCHED_PRIO_MIN)
    1118                 :          0 :                 badusage("IO scheduler priority less than min");
    1119         [ #  # ]:          0 :         if (io_sched->priority > IO_SCHED_PRIO_MAX)
    1120                 :          0 :                 badusage("IO scheduler priority greater than max");
    1121                 :          0 : }
    1122                 :            : 
    1123                 :            : static void
    1124                 :          0 : set_proc_schedule(struct res_schedule *sched)
    1125                 :            : {
    1126                 :            : #if defined(_POSIX_PRIORITY_SCHEDULING) && _POSIX_PRIORITY_SCHEDULING > 0
    1127                 :            :         struct sched_param param;
    1128                 :            : 
    1129                 :          0 :         param.sched_priority = sched->priority;
    1130                 :            : 
    1131         [ #  # ]:          0 :         if (sched_setscheduler(getpid(), sched->policy, &param) == -1)
    1132                 :          0 :                 fatale("unable to set process scheduler");
    1133                 :            : #endif
    1134                 :          0 : }
    1135                 :            : 
    1136                 :            : #ifdef HAVE_IOPRIO_SET
    1137                 :            : static inline int
    1138                 :          0 : ioprio_set(int which, int who, int ioprio)
    1139                 :            : {
    1140                 :          0 :         return syscall(SYS_ioprio_set, which, who, ioprio);
    1141                 :            : }
    1142                 :            : #endif
    1143                 :            : 
    1144                 :            : static void
    1145                 :          0 : set_io_schedule(struct res_schedule *sched)
    1146                 :            : {
    1147                 :            : #ifdef HAVE_IOPRIO_SET
    1148                 :            :         int io_sched_mask;
    1149                 :            : 
    1150                 :          0 :         io_sched_mask = IOPRIO_PRIO_VALUE(sched->policy, sched->priority);
    1151         [ #  # ]:          0 :         if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), io_sched_mask) == -1)
    1152                 :          0 :                 warning("unable to alter IO priority to mask %i (%s)\n",
    1153                 :          0 :                         io_sched_mask, strerror(errno));
    1154                 :            : #endif
    1155                 :          0 : }
    1156                 :            : 
    1157                 :            : static void
    1158                 :          0 : parse_schedule_item(const char *string, struct schedule_item *item)
    1159                 :            : {
    1160                 :            :         const char *after_hyph;
    1161                 :            : 
    1162         [ #  # ]:          0 :         if (strcmp(string, "forever") == 0) {
    1163                 :          0 :                 item->type = sched_forever;
    1164         [ #  # ]:          0 :         } else if (isdigit(string[0])) {
    1165                 :          0 :                 item->type = sched_timeout;
    1166         [ #  # ]:          0 :                 if (parse_unsigned(string, 10, &item->value) != 0)
    1167                 :          0 :                         badusage("invalid timeout value in schedule");
    1168   [ #  #  #  # ]:          0 :         } else if ((after_hyph = string + (string[0] == '-')) &&
    1169                 :          0 :                    parse_signal(after_hyph, &item->value) == 0) {
    1170                 :          0 :                 item->type = sched_signal;
    1171                 :            :         } else {
    1172                 :          0 :                 badusage("invalid schedule item (must be [-]<signal-name>, "
    1173                 :            :                          "-<signal-number>, <timeout> or 'forever'");
    1174                 :            :         }
    1175                 :          0 : }
    1176                 :            : 
    1177                 :            : static void
    1178                 :          0 : parse_schedule(const char *schedule_str)
    1179                 :            : {
    1180                 :            :         char item_buf[20];
    1181                 :            :         const char *slash;
    1182                 :            :         int count, repeatat;
    1183                 :            :         size_t str_len;
    1184                 :            : 
    1185                 :          0 :         count = 0;
    1186         [ #  # ]:          0 :         for (slash = schedule_str; *slash; slash++)
    1187         [ #  # ]:          0 :                 if (*slash == '/')
    1188                 :          0 :                         count++;
    1189                 :            : 
    1190         [ #  # ]:          0 :         schedule_length = (count == 0) ? 4 : count + 1;
    1191                 :          0 :         schedule = xmalloc(sizeof(*schedule) * schedule_length);
    1192                 :            : 
    1193         [ #  # ]:          0 :         if (count == 0) {
    1194                 :          0 :                 schedule[0].type = sched_signal;
    1195                 :          0 :                 schedule[0].value = signal_nr;
    1196                 :          0 :                 parse_schedule_item(schedule_str, &schedule[1]);
    1197         [ #  # ]:          0 :                 if (schedule[1].type != sched_timeout) {
    1198                 :          0 :                         badusage("--retry takes timeout, or schedule list"
    1199                 :            :                                  " of at least two items");
    1200                 :            :                 }
    1201                 :          0 :                 schedule[2].type = sched_signal;
    1202                 :          0 :                 schedule[2].value = SIGKILL;
    1203                 :          0 :                 schedule[3] = schedule[1];
    1204                 :            :         } else {
    1205                 :          0 :                 count = 0;
    1206                 :          0 :                 repeatat = -1;
    1207         [ #  # ]:          0 :                 while (*schedule_str) {
    1208                 :          0 :                         slash = strchrnul(schedule_str, '/');
    1209                 :          0 :                         str_len = (size_t)(slash - schedule_str);
    1210         [ #  # ]:          0 :                         if (str_len >= sizeof(item_buf))
    1211                 :          0 :                                 badusage("invalid schedule item: far too long"
    1212                 :            :                                          " (you must delimit items with slashes)");
    1213                 :          0 :                         memcpy(item_buf, schedule_str, str_len);
    1214                 :          0 :                         item_buf[str_len] = '\0';
    1215         [ #  # ]:          0 :                         schedule_str = *slash ? slash + 1 : slash;
    1216                 :            : 
    1217                 :          0 :                         parse_schedule_item(item_buf, &schedule[count]);
    1218         [ #  # ]:          0 :                         if (schedule[count].type == sched_forever) {
    1219         [ #  # ]:          0 :                                 if (repeatat >= 0)
    1220                 :          0 :                                         badusage("invalid schedule: 'forever'"
    1221                 :            :                                                  " appears more than once");
    1222                 :          0 :                                 repeatat = count;
    1223                 :          0 :                                 continue;
    1224                 :            :                         }
    1225                 :          0 :                         count++;
    1226                 :            :                 }
    1227         [ #  # ]:          0 :                 if (repeatat == count)
    1228                 :          0 :                         badusage("invalid schedule: 'forever' appears last, "
    1229                 :            :                                  "nothing to repeat");
    1230         [ #  # ]:          0 :                 if (repeatat >= 0) {
    1231                 :          0 :                         schedule[count].type = sched_goto;
    1232                 :          0 :                         schedule[count].value = repeatat;
    1233                 :          0 :                         count++;
    1234                 :            :                 }
    1235         [ #  # ]:          0 :                 if (count != schedule_length)
    1236                 :          0 :                         BUG("count=%d != schedule_length=%d",
    1237                 :            :                             count, schedule_length);
    1238                 :            :         }
    1239                 :          0 : }
    1240                 :            : 
    1241                 :            : static void
    1242                 :          0 : set_action(enum action_code new_action)
    1243                 :            : {
    1244         [ #  # ]:          0 :         if (action == new_action)
    1245                 :          0 :                 return;
    1246                 :            : 
    1247         [ #  # ]:          0 :         if (action != ACTION_NONE)
    1248                 :          0 :                 badusage("only one command can be specified");
    1249                 :            : 
    1250                 :          0 :         action = new_action;
    1251                 :            : }
    1252                 :            : 
    1253                 :            : #define OPT_PID         500
    1254                 :            : #define OPT_PPID        501
    1255                 :            : #define OPT_RM_PIDFILE  502
    1256                 :            : #define OPT_NOTIFY_AWAIT        503
    1257                 :            : #define OPT_NOTIFY_TIMEOUT      504
    1258                 :            : 
    1259                 :            : static void
    1260                 :          0 : parse_options(int argc, char * const *argv)
    1261                 :            : {
    1262                 :            :         static struct option longopts[] = {
    1263                 :            :                 { "help",       0, NULL, 'H'},
    1264                 :            :                 { "stop",       0, NULL, 'K'},
    1265                 :            :                 { "start",      0, NULL, 'S'},
    1266                 :            :                 { "status",     0, NULL, 'T'},
    1267                 :            :                 { "version",    0, NULL, 'V'},
    1268                 :            :                 { "startas",    1, NULL, 'a'},
    1269                 :            :                 { "name",       1, NULL, 'n'},
    1270                 :            :                 { "oknodo",     0, NULL, 'o'},
    1271                 :            :                 { "pid",        1, NULL, OPT_PID},
    1272                 :            :                 { "ppid",       1, NULL, OPT_PPID},
    1273                 :            :                 { "pidfile",    1, NULL, 'p'},
    1274                 :            :                 { "quiet",      0, NULL, 'q'},
    1275                 :            :                 { "signal",     1, NULL, 's'},
    1276                 :            :                 { "test",       0, NULL, 't'},
    1277                 :            :                 { "user",       1, NULL, 'u'},
    1278                 :            :                 { "group",      1, NULL, 'g'},
    1279                 :            :                 { "chroot",     1, NULL, 'r'},
    1280                 :            :                 { "verbose",    0, NULL, 'v'},
    1281                 :            :                 { "exec",       1, NULL, 'x'},
    1282                 :            :                 { "chuid",      1, NULL, 'c'},
    1283                 :            :                 { "nicelevel",          1, NULL, 'N'},
    1284                 :            :                 { "procsched",          1, NULL, 'P'},
    1285                 :            :                 { "iosched",    1, NULL, 'I'},
    1286                 :            :                 { "umask",      1, NULL, 'k'},
    1287                 :            :                 { "background",         0, NULL, 'b'},
    1288                 :            :                 { "notify-await", 0, NULL, OPT_NOTIFY_AWAIT},
    1289                 :            :                 { "notify-timeout", 1, NULL, OPT_NOTIFY_TIMEOUT},
    1290                 :            :                 { "no-close",   0, NULL, 'C'},
    1291                 :            :                 { "output",     1, NULL, 'O'},
    1292                 :            :                 { "make-pidfile", 0, NULL, 'm'},
    1293                 :            :                 { "remove-pidfile", 0, NULL, OPT_RM_PIDFILE},
    1294                 :            :                 { "retry",      1, NULL, 'R'},
    1295                 :            :                 { "chdir",      1, NULL, 'd'},
    1296                 :            :                 { NULL,           0, NULL, 0  }
    1297                 :            :         };
    1298                 :          0 :         const char *pid_str = NULL;
    1299                 :          0 :         const char *ppid_str = NULL;
    1300                 :          0 :         const char *umask_str = NULL;
    1301                 :          0 :         const char *signal_str = NULL;
    1302                 :          0 :         const char *schedule_str = NULL;
    1303                 :          0 :         const char *proc_schedule_str = NULL;
    1304                 :          0 :         const char *io_schedule_str = NULL;
    1305                 :          0 :         const char *notify_timeout_str = NULL;
    1306                 :            :         size_t changeuser_len;
    1307                 :            :         int c;
    1308                 :            : 
    1309                 :            :         for (;;) {
    1310                 :          0 :                 c = getopt_long(argc, argv,
    1311                 :            :                                 "HKSVTa:n:op:qr:s:tu:vx:c:N:P:I:k:bCO:mR:g:d:",
    1312                 :            :                                 longopts, NULL);
    1313         [ #  # ]:          0 :                 if (c == -1)
    1314                 :          0 :                         break;
    1315   [ #  #  #  #  :          0 :                 switch (c) {
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
    1316                 :          0 :                 case 'H':  /* --help */
    1317                 :          0 :                         usage();
    1318                 :          0 :                         exit(0);
    1319                 :          0 :                 case 'K':  /* --stop */
    1320                 :          0 :                         set_action(ACTION_STOP);
    1321                 :          0 :                         break;
    1322                 :          0 :                 case 'S':  /* --start */
    1323                 :          0 :                         set_action(ACTION_START);
    1324                 :          0 :                         break;
    1325                 :          0 :                 case 'T':  /* --status */
    1326                 :          0 :                         set_action(ACTION_STATUS);
    1327                 :          0 :                         break;
    1328                 :          0 :                 case 'V':  /* --version */
    1329                 :          0 :                         do_version();
    1330                 :          0 :                         exit(0);
    1331                 :          0 :                 case 'a':  /* --startas <pathname> */
    1332                 :          0 :                         startas = optarg;
    1333                 :          0 :                         break;
    1334                 :          0 :                 case 'n':  /* --name <process-name> */
    1335                 :          0 :                         match_mode |= MATCH_NAME;
    1336                 :          0 :                         cmdname = optarg;
    1337                 :          0 :                         break;
    1338                 :          0 :                 case 'o':  /* --oknodo */
    1339                 :          0 :                         exitnodo = 0;
    1340                 :          0 :                         break;
    1341                 :          0 :                 case OPT_PID: /* --pid <pid> */
    1342                 :          0 :                         match_mode |= MATCH_PID;
    1343                 :          0 :                         pid_str = optarg;
    1344                 :          0 :                         break;
    1345                 :          0 :                 case OPT_PPID: /* --ppid <ppid> */
    1346                 :          0 :                         match_mode |= MATCH_PPID;
    1347                 :          0 :                         ppid_str = optarg;
    1348                 :          0 :                         break;
    1349                 :          0 :                 case 'p':  /* --pidfile <pid-file> */
    1350                 :          0 :                         match_mode |= MATCH_PIDFILE;
    1351                 :          0 :                         pidfile = optarg;
    1352                 :          0 :                         break;
    1353                 :          0 :                 case 'q':  /* --quiet */
    1354                 :          0 :                         quietmode = true;
    1355                 :          0 :                         break;
    1356                 :          0 :                 case 's':  /* --signal <signal> */
    1357                 :          0 :                         signal_str = optarg;
    1358                 :          0 :                         break;
    1359                 :          0 :                 case 't':  /* --test */
    1360                 :          0 :                         testmode = true;
    1361                 :          0 :                         break;
    1362                 :          0 :                 case 'u':  /* --user <username>|<uid> */
    1363                 :          0 :                         match_mode |= MATCH_USER;
    1364                 :          0 :                         userspec = optarg;
    1365                 :          0 :                         break;
    1366                 :          0 :                 case 'v':  /* --verbose */
    1367                 :          0 :                         quietmode = -1;
    1368                 :          0 :                         break;
    1369                 :          0 :                 case 'x':  /* --exec <executable> */
    1370                 :          0 :                         match_mode |= MATCH_EXEC;
    1371                 :          0 :                         execname = optarg;
    1372                 :          0 :                         break;
    1373                 :          0 :                 case 'c':  /* --chuid <username>|<uid> */
    1374                 :          0 :                         free(changeuser);
    1375                 :            :                         /* We copy the string just in case we need the
    1376                 :            :                          * argument later. */
    1377                 :          0 :                         changeuser_len = strcspn(optarg, ":");
    1378                 :          0 :                         changeuser = xstrndup(optarg, changeuser_len);
    1379         [ #  # ]:          0 :                         if (optarg[changeuser_len] == ':') {
    1380         [ #  # ]:          0 :                                 if (optarg[changeuser_len + 1] == '\0')
    1381                 :          0 :                                         fatal("missing group name");
    1382                 :          0 :                                 changegroup = optarg + changeuser_len + 1;
    1383                 :            :                         }
    1384                 :          0 :                         break;
    1385                 :          0 :                 case 'g':  /* --group <group>|<gid> */
    1386                 :          0 :                         changegroup = optarg;
    1387                 :          0 :                         break;
    1388                 :          0 :                 case 'r':  /* --chroot /new/root */
    1389                 :          0 :                         changeroot = optarg;
    1390                 :          0 :                         break;
    1391                 :          0 :                 case 'N':  /* --nice */
    1392                 :          0 :                         nicelevel = atoi(optarg);
    1393                 :          0 :                         break;
    1394                 :          0 :                 case 'P':  /* --procsched */
    1395                 :          0 :                         proc_schedule_str = optarg;
    1396                 :          0 :                         break;
    1397                 :          0 :                 case 'I':  /* --iosched */
    1398                 :          0 :                         io_schedule_str = optarg;
    1399                 :          0 :                         break;
    1400                 :          0 :                 case 'k':  /* --umask <mask> */
    1401                 :          0 :                         umask_str = optarg;
    1402                 :          0 :                         break;
    1403                 :          0 :                 case 'b':  /* --background */
    1404                 :          0 :                         background = true;
    1405                 :          0 :                         break;
    1406                 :          0 :                 case OPT_NOTIFY_AWAIT:
    1407                 :          0 :                         notify_await = true;
    1408                 :          0 :                         break;
    1409                 :          0 :                 case OPT_NOTIFY_TIMEOUT:
    1410                 :          0 :                         notify_timeout_str = optarg;
    1411                 :          0 :                         break;
    1412                 :          0 :                 case 'C': /* --no-close */
    1413                 :          0 :                         close_io = false;
    1414                 :          0 :                         break;
    1415                 :          0 :                 case 'O': /* --outout <filename> */
    1416                 :          0 :                         output_io = optarg;
    1417                 :          0 :                         break;
    1418                 :          0 :                 case 'm':  /* --make-pidfile */
    1419                 :          0 :                         mpidfile = true;
    1420                 :          0 :                         break;
    1421                 :          0 :                 case OPT_RM_PIDFILE: /* --remove-pidfile */
    1422                 :          0 :                         rpidfile = true;
    1423                 :          0 :                         break;
    1424                 :          0 :                 case 'R':  /* --retry <schedule>|<timeout> */
    1425                 :          0 :                         schedule_str = optarg;
    1426                 :          0 :                         break;
    1427                 :          0 :                 case 'd':  /* --chdir /new/dir */
    1428                 :          0 :                         changedir = optarg;
    1429                 :          0 :                         break;
    1430                 :          0 :                 default:
    1431                 :            :                         /* Message printed by getopt. */
    1432                 :          0 :                         badusage(NULL);
    1433                 :            :                 }
    1434                 :            :         }
    1435                 :            : 
    1436         [ #  # ]:          0 :         if (pid_str != NULL) {
    1437         [ #  # ]:          0 :                 if (parse_pid(pid_str, &match_pid) != 0)
    1438                 :          0 :                         badusage("pid value must be a number greater than 0");
    1439                 :            :         }
    1440                 :            : 
    1441         [ #  # ]:          0 :         if (ppid_str != NULL) {
    1442         [ #  # ]:          0 :                 if (parse_pid(ppid_str, &match_ppid) != 0)
    1443                 :          0 :                         badusage("ppid value must be a number greater than 0");
    1444                 :            :         }
    1445                 :            : 
    1446         [ #  # ]:          0 :         if (signal_str != NULL) {
    1447         [ #  # ]:          0 :                 if (parse_signal(signal_str, &signal_nr) != 0)
    1448                 :          0 :                         badusage("signal value must be numeric or name"
    1449                 :            :                                  " of signal (KILL, INT, ...)");
    1450                 :            :         }
    1451                 :            : 
    1452         [ #  # ]:          0 :         if (schedule_str != NULL) {
    1453                 :          0 :                 parse_schedule(schedule_str);
    1454                 :            :         }
    1455                 :            : 
    1456         [ #  # ]:          0 :         if (proc_schedule_str != NULL)
    1457                 :          0 :                 parse_proc_schedule(proc_schedule_str);
    1458                 :            : 
    1459         [ #  # ]:          0 :         if (io_schedule_str != NULL)
    1460                 :          0 :                 parse_io_schedule(io_schedule_str);
    1461                 :            : 
    1462         [ #  # ]:          0 :         if (umask_str != NULL) {
    1463         [ #  # ]:          0 :                 if (parse_umask(umask_str, &umask_value) != 0)
    1464                 :          0 :                         badusage("umask value must be a positive number");
    1465                 :            :         }
    1466                 :            : 
    1467   [ #  #  #  # ]:          0 :         if (output_io != NULL && output_io[0] != '/')
    1468                 :          0 :                 badusage("--output file needs to be an absolute filename");
    1469                 :            : 
    1470         [ #  # ]:          0 :         if (notify_timeout_str != NULL)
    1471         [ #  # ]:          0 :                 if (parse_unsigned(notify_timeout_str, 10, &notify_timeout) != 0)
    1472                 :          0 :                         badusage("invalid notify timeout value");
    1473                 :            : 
    1474         [ #  # ]:          0 :         if (action == ACTION_NONE)
    1475                 :          0 :                 badusage("need one of --start or --stop or --status");
    1476                 :            : 
    1477         [ #  # ]:          0 :         if (match_mode == MATCH_NONE ||
    1478   [ #  #  #  #  :          0 :             (!execname && !cmdname && !userspec &&
             #  #  #  # ]
    1479   [ #  #  #  # ]:          0 :              !pid_str && !ppid_str && !pidfile))
    1480                 :          0 :                 badusage("need at least one of --exec, --pid, --ppid, --pidfile, --user or --name");
    1481                 :            : 
    1482                 :            : #ifdef PROCESS_NAME_SIZE
    1483   [ #  #  #  # ]:          0 :         if (cmdname && strlen(cmdname) > PROCESS_NAME_SIZE)
    1484                 :          0 :                 warning("this system is not able to track process names\n"
    1485                 :            :                         "longer than %d characters, please use --exec "
    1486                 :            :                         "instead of --name.\n", PROCESS_NAME_SIZE);
    1487                 :            : #endif
    1488                 :            : 
    1489         [ #  # ]:          0 :         if (!startas)
    1490                 :          0 :                 startas = execname;
    1491                 :            : 
    1492   [ #  #  #  # ]:          0 :         if (action == ACTION_START && !startas)
    1493                 :          0 :                 badusage("--start needs --exec or --startas");
    1494                 :            : 
    1495   [ #  #  #  # ]:          0 :         if (mpidfile && pidfile == NULL)
    1496                 :          0 :                 badusage("--make-pidfile requires --pidfile");
    1497   [ #  #  #  # ]:          0 :         if (rpidfile && pidfile == NULL)
    1498                 :          0 :                 badusage("--remove-pidfile requires --pidfile");
    1499                 :            : 
    1500   [ #  #  #  # ]:          0 :         if (pid_str && pidfile)
    1501                 :          0 :                 badusage("need either --pid or --pidfile, not both");
    1502                 :            : 
    1503   [ #  #  #  # ]:          0 :         if (background && action != ACTION_START)
    1504                 :          0 :                 badusage("--background is only relevant with --start");
    1505                 :            : 
    1506   [ #  #  #  # ]:          0 :         if (!close_io && !background)
    1507                 :          0 :                 badusage("--no-close is only relevant with --background");
    1508   [ #  #  #  # ]:          0 :         if (output_io && !background)
    1509                 :          0 :                 badusage("--output is only relevant with --background");
    1510                 :            : 
    1511   [ #  #  #  # ]:          0 :         if (close_io && output_io == NULL)
    1512                 :          0 :                 output_io = "/dev/null";
    1513                 :          0 : }
    1514                 :            : 
    1515                 :            : static void
    1516                 :          0 : setup_options(void)
    1517                 :            : {
    1518         [ #  # ]:          0 :         if (execname) {
    1519                 :            :                 char *fullexecname;
    1520                 :            : 
    1521                 :            :                 /* If it's a relative path, normalize it. */
    1522         [ #  # ]:          0 :                 if (execname[0] != '/')
    1523                 :          0 :                         execname = newpath(changedir, execname);
    1524                 :            : 
    1525         [ #  # ]:          0 :                 if (changeroot)
    1526                 :          0 :                         fullexecname = newpath(changeroot, execname);
    1527                 :            :                 else
    1528                 :          0 :                         fullexecname = execname;
    1529                 :            : 
    1530         [ #  # ]:          0 :                 if (stat(fullexecname, &exec_stat))
    1531                 :          0 :                         fatale("unable to stat %s", fullexecname);
    1532                 :            : 
    1533         [ #  # ]:          0 :                 if (fullexecname != execname)
    1534                 :          0 :                         free(fullexecname);
    1535                 :            :         }
    1536                 :            : 
    1537   [ #  #  #  # ]:          0 :         if (userspec && parse_unsigned(userspec, 10, &user_id) < 0) {
    1538                 :            :                 struct passwd *pw;
    1539                 :            : 
    1540                 :          0 :                 pw = getpwnam(userspec);
    1541         [ #  # ]:          0 :                 if (!pw)
    1542                 :          0 :                         fatale("user '%s' not found", userspec);
    1543                 :            : 
    1544                 :          0 :                 user_id = pw->pw_uid;
    1545                 :            :         }
    1546                 :            : 
    1547   [ #  #  #  # ]:          0 :         if (changegroup && parse_unsigned(changegroup, 10, &runas_gid) < 0) {
    1548                 :            :                 struct group *gr;
    1549                 :            : 
    1550                 :          0 :                 gr = getgrnam(changegroup);
    1551         [ #  # ]:          0 :                 if (!gr)
    1552                 :          0 :                         fatale("group '%s' not found", changegroup);
    1553                 :          0 :                 changegroup = gr->gr_name;
    1554                 :          0 :                 runas_gid = gr->gr_gid;
    1555                 :            :         }
    1556         [ #  # ]:          0 :         if (changeuser) {
    1557                 :            :                 struct passwd *pw;
    1558                 :            :                 struct stat st;
    1559                 :            : 
    1560         [ #  # ]:          0 :                 if (parse_unsigned(changeuser, 10, &runas_uid) == 0)
    1561                 :          0 :                         pw = getpwuid(runas_uid);
    1562                 :            :                 else
    1563                 :          0 :                         pw = getpwnam(changeuser);
    1564         [ #  # ]:          0 :                 if (!pw)
    1565                 :          0 :                         fatale("user '%s' not found", changeuser);
    1566                 :          0 :                 changeuser = pw->pw_name;
    1567                 :          0 :                 runas_uid = pw->pw_uid;
    1568         [ #  # ]:          0 :                 if (changegroup == NULL) {
    1569                 :            :                         /* Pass the default group of this user. */
    1570                 :          0 :                         changegroup = ""; /* Just empty. */
    1571                 :          0 :                         runas_gid = pw->pw_gid;
    1572                 :            :                 }
    1573         [ #  # ]:          0 :                 if (stat(pw->pw_dir, &st) == 0)
    1574                 :          0 :                         setenv("HOME", pw->pw_dir, 1);
    1575                 :            :         }
    1576                 :          0 : }
    1577                 :            : 
    1578                 :            : #if defined(OS_Linux)
    1579                 :            : static const char *
    1580                 :          0 : proc_status_field(pid_t pid, const char *field)
    1581                 :            : {
    1582                 :            :         static char *line = NULL;
    1583                 :            :         static size_t line_size = 0;
    1584                 :            : 
    1585                 :            :         FILE *fp;
    1586                 :            :         char filename[32];
    1587                 :          0 :         char *value = NULL;
    1588                 :            :         ssize_t line_len;
    1589                 :          0 :         size_t field_len = strlen(field);
    1590                 :            : 
    1591                 :          0 :         sprintf(filename, "/proc/%d/status", pid);
    1592                 :          0 :         fp = fopen(filename, "r");
    1593         [ #  # ]:          0 :         if (!fp)
    1594                 :          0 :                 return NULL;
    1595         [ #  # ]:          0 :         while ((line_len = getline(&line, &line_size, fp)) >= 0) {
    1596         [ #  # ]:          0 :                 if (strncasecmp(line, field, field_len) == 0) {
    1597                 :          0 :                         line[line_len - 1] = '\0';
    1598                 :            : 
    1599                 :          0 :                         value = line + field_len;
    1600         [ #  # ]:          0 :                         while (isspace(*value))
    1601                 :          0 :                                 value++;
    1602                 :            : 
    1603                 :          0 :                         break;
    1604                 :            :                 }
    1605                 :            :         }
    1606                 :          0 :         fclose(fp);
    1607                 :            : 
    1608                 :          0 :         return value;
    1609                 :            : }
    1610                 :            : #elif defined(OS_AIX)
    1611                 :            : static bool
    1612                 :            : proc_get_psinfo(pid_t pid, struct psinfo *psinfo)
    1613                 :            : {
    1614                 :            :         char filename[64];
    1615                 :            :         FILE *fp;
    1616                 :            : 
    1617                 :            :         sprintf(filename, "/proc/%d/psinfo", pid);
    1618                 :            :         fp = fopen(filename, "r");
    1619                 :            :         if (!fp)
    1620                 :            :                 return false;
    1621                 :            :         if (fread(psinfo, sizeof(*psinfo), 1, fp) == 0) {
    1622                 :            :                 fclose(fp);
    1623                 :            :                 return false;
    1624                 :            :         }
    1625                 :            :         if (ferror(fp)) {
    1626                 :            :                 fclose(fp);
    1627                 :            :                 return false;
    1628                 :            :         }
    1629                 :            : 
    1630                 :            :         fclose(fp);
    1631                 :            : 
    1632                 :            :         return true;
    1633                 :            : }
    1634                 :            : #elif defined(OS_Hurd)
    1635                 :            : static void
    1636                 :            : init_procset(void)
    1637                 :            : {
    1638                 :            :         struct ps_context *context;
    1639                 :            :         error_t err;
    1640                 :            : 
    1641                 :            :         err = ps_context_create(getproc(), &context);
    1642                 :            :         if (err)
    1643                 :            :                 error(1, err, "ps_context_create");
    1644                 :            : 
    1645                 :            :         err = proc_stat_list_create(context, &procset);
    1646                 :            :         if (err)
    1647                 :            :                 error(1, err, "proc_stat_list_create");
    1648                 :            : 
    1649                 :            :         err = proc_stat_list_add_all(procset, 0, 0);
    1650                 :            :         if (err)
    1651                 :            :                 error(1, err, "proc_stat_list_add_all");
    1652                 :            : }
    1653                 :            : 
    1654                 :            : static struct proc_stat *
    1655                 :            : get_proc_stat(pid_t pid, ps_flags_t flags)
    1656                 :            : {
    1657                 :            :         struct proc_stat *ps;
    1658                 :            :         ps_flags_t wanted_flags = PSTAT_PID | flags;
    1659                 :            : 
    1660                 :            :         if (!procset)
    1661                 :            :                 init_procset();
    1662                 :            : 
    1663                 :            :         ps = proc_stat_list_pid_proc_stat(procset, pid);
    1664                 :            :         if (!ps)
    1665                 :            :                 return NULL;
    1666                 :            :         if (proc_stat_set_flags(ps, wanted_flags))
    1667                 :            :                 return NULL;
    1668                 :            :         if ((proc_stat_flags(ps) & wanted_flags) != wanted_flags)
    1669                 :            :                 return NULL;
    1670                 :            : 
    1671                 :            :         return ps;
    1672                 :            : }
    1673                 :            : #elif defined(HAVE_KVM_H)
    1674                 :            : static kvm_t *
    1675                 :            : ssd_kvm_open(void)
    1676                 :            : {
    1677                 :            :         kvm_t *kd;
    1678                 :            :         char errbuf[_POSIX2_LINE_MAX];
    1679                 :            : 
    1680                 :            :         kd = kvm_openfiles(NULL, KVM_MEMFILE, NULL, O_RDONLY, errbuf);
    1681                 :            :         if (kd == NULL)
    1682                 :            :                 errx(1, "%s", errbuf);
    1683                 :            : 
    1684                 :            :         return kd;
    1685                 :            : }
    1686                 :            : 
    1687                 :            : static struct kinfo_proc *
    1688                 :            : ssd_kvm_get_procs(kvm_t *kd, int op, int arg, int *count)
    1689                 :            : {
    1690                 :            :         struct kinfo_proc *kp;
    1691                 :            :         int lcount;
    1692                 :            : 
    1693                 :            :         if (count == NULL)
    1694                 :            :                 count = &lcount;
    1695                 :            :         *count = 0;
    1696                 :            : 
    1697                 :            : #if defined(OS_OpenBSD)
    1698                 :            :         kp = kvm_getprocs(kd, op, arg, sizeof(*kp), count);
    1699                 :            : #else
    1700                 :            :         kp = kvm_getprocs(kd, op, arg, count);
    1701                 :            : #endif
    1702                 :            :         if (kp == NULL && errno != ESRCH)
    1703                 :            :                 errx(1, "%s", kvm_geterr(kd));
    1704                 :            : 
    1705                 :            :         return kp;
    1706                 :            : }
    1707                 :            : #endif
    1708                 :            : 
    1709                 :            : #if defined(OS_Linux)
    1710                 :            : static bool
    1711                 :          0 : pid_is_exec(pid_t pid, const struct stat *esb)
    1712                 :            : {
    1713                 :            :         char lname[32];
    1714                 :            :         char lcontents[_POSIX_PATH_MAX + 1];
    1715                 :            :         char *filename;
    1716                 :          0 :         const char deleted[] = " (deleted)";
    1717                 :            :         int nread;
    1718                 :            :         struct stat sb;
    1719                 :            : 
    1720                 :          0 :         sprintf(lname, "/proc/%d/exe", pid);
    1721                 :          0 :         nread = readlink(lname, lcontents, sizeof(lcontents) - 1);
    1722         [ #  # ]:          0 :         if (nread == -1)
    1723                 :          0 :                 return false;
    1724                 :            : 
    1725                 :          0 :         filename = lcontents;
    1726                 :          0 :         filename[nread] = '\0';
    1727                 :            : 
    1728                 :            :         /* OpenVZ kernels contain a bogus patch that instead of appending,
    1729                 :            :          * prepends the deleted marker. Workaround those. Otherwise handle
    1730                 :            :          * the normal appended marker. */
    1731         [ #  # ]:          0 :         if (strncmp(filename, deleted, strlen(deleted)) == 0)
    1732                 :          0 :                 filename += strlen(deleted);
    1733         [ #  # ]:          0 :         else if (strcmp(filename + nread - strlen(deleted), deleted) == 0)
    1734                 :          0 :                 filename[nread - strlen(deleted)] = '\0';
    1735                 :            : 
    1736         [ #  # ]:          0 :         if (stat(filename, &sb) != 0)
    1737                 :          0 :                 return false;
    1738                 :            : 
    1739   [ #  #  #  # ]:          0 :         return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
    1740                 :            : }
    1741                 :            : #elif defined(OS_AIX)
    1742                 :            : static bool
    1743                 :            : pid_is_exec(pid_t pid, const struct stat *esb)
    1744                 :            : {
    1745                 :            :         struct stat sb;
    1746                 :            :         char filename[64];
    1747                 :            : 
    1748                 :            :         sprintf(filename, "/proc/%d/object/a.out", pid);
    1749                 :            : 
    1750                 :            :         if (stat(filename, &sb) != 0)
    1751                 :            :                 return false;
    1752                 :            : 
    1753                 :            :         return sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino;
    1754                 :            : }
    1755                 :            : #elif defined(OS_Hurd)
    1756                 :            : static bool
    1757                 :            : pid_is_exec(pid_t pid, const struct stat *esb)
    1758                 :            : {
    1759                 :            :         struct proc_stat *ps;
    1760                 :            :         struct stat sb;
    1761                 :            :         const char *filename;
    1762                 :            : 
    1763                 :            :         ps = get_proc_stat(pid, PSTAT_ARGS);
    1764                 :            :         if (ps == NULL)
    1765                 :            :                 return false;
    1766                 :            : 
    1767                 :            :         /* On old Hurd systems we have to use the argv[0] value, because
    1768                 :            :          * there is nothing better. */
    1769                 :            :         filename = proc_stat_args(ps);
    1770                 :            : #ifdef PSTAT_EXE
    1771                 :            :         /* On new Hurd systems we can use the correct value, as long
    1772                 :            :          * as it's not NULL nor empty, as it was the case on the first
    1773                 :            :          * implementation. */
    1774                 :            :         if (proc_stat_set_flags(ps, PSTAT_EXE) == 0 &&
    1775                 :            :             proc_stat_flags(ps) & PSTAT_EXE &&
    1776                 :            :             proc_stat_exe(ps) != NULL &&
    1777                 :            :             proc_stat_exe(ps)[0] != '\0')
    1778                 :            :                 filename = proc_stat_exe(ps);
    1779                 :            : #endif
    1780                 :            : 
    1781                 :            :         if (stat(filename, &sb) != 0)
    1782                 :            :                 return false;
    1783                 :            : 
    1784                 :            :         return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
    1785                 :            : }
    1786                 :            : #elif defined(OS_Darwin)
    1787                 :            : static bool
    1788                 :            : pid_is_exec(pid_t pid, const struct stat *esb)
    1789                 :            : {
    1790                 :            :         struct stat sb;
    1791                 :            :         char pathname[_POSIX_PATH_MAX];
    1792                 :            : 
    1793                 :            :         if (proc_pidpath(pid, pathname, sizeof(pathname)) < 0)
    1794                 :            :                 return false;
    1795                 :            : 
    1796                 :            :         if (stat(pathname, &sb) != 0)
    1797                 :            :                 return false;
    1798                 :            : 
    1799                 :            :         return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
    1800                 :            : }
    1801                 :            : #elif defined(OS_HPUX)
    1802                 :            : static bool
    1803                 :            : pid_is_exec(pid_t pid, const struct stat *esb)
    1804                 :            : {
    1805                 :            :         struct pst_status pst;
    1806                 :            : 
    1807                 :            :         if (pstat_getproc(&pst, sizeof(pst), (size_t)0, (int)pid) < 0)
    1808                 :            :                 return false;
    1809                 :            :         return ((dev_t)pst.pst_text.psf_fsid.psfs_id == esb->st_dev &&
    1810                 :            :                 (ino_t)pst.pst_text.psf_fileid == esb->st_ino);
    1811                 :            : }
    1812                 :            : #elif defined(OS_FreeBSD)
    1813                 :            : static bool
    1814                 :            : pid_is_exec(pid_t pid, const struct stat *esb)
    1815                 :            : {
    1816                 :            :         struct stat sb;
    1817                 :            :         int error, mib[4];
    1818                 :            :         size_t len;
    1819                 :            :         char pathname[PATH_MAX];
    1820                 :            : 
    1821                 :            :         mib[0] = CTL_KERN;
    1822                 :            :         mib[1] = KERN_PROC;
    1823                 :            :         mib[2] = KERN_PROC_PATHNAME;
    1824                 :            :         mib[3] = pid;
    1825                 :            :         len = sizeof(pathname);
    1826                 :            : 
    1827                 :            :         error = sysctl(mib, 4, pathname, &len, NULL, 0);
    1828                 :            :         if (error != 0 && errno != ESRCH)
    1829                 :            :                 return false;
    1830                 :            :         if (len == 0)
    1831                 :            :                 pathname[0] = '\0';
    1832                 :            : 
    1833                 :            :         if (stat(pathname, &sb) != 0)
    1834                 :            :                 return false;
    1835                 :            : 
    1836                 :            :         return (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
    1837                 :            : }
    1838                 :            : #elif defined(HAVE_KVM_H)
    1839                 :            : static bool
    1840                 :            : pid_is_exec(pid_t pid, const struct stat *esb)
    1841                 :            : {
    1842                 :            :         kvm_t *kd;
    1843                 :            :         int argv_len = 0;
    1844                 :            :         struct kinfo_proc *kp;
    1845                 :            :         struct stat sb;
    1846                 :            :         char buf[_POSIX2_LINE_MAX];
    1847                 :            :         char **pid_argv_p;
    1848                 :            :         char *start_argv_0_p, *end_argv_0_p;
    1849                 :            :         bool res = false;
    1850                 :            : 
    1851                 :            :         kd = ssd_kvm_open();
    1852                 :            :         kp = ssd_kvm_get_procs(kd, KERN_PROC_PID, pid, NULL);
    1853                 :            :         if (kp == NULL)
    1854                 :            :                 goto cleanup;
    1855                 :            : 
    1856                 :            :         pid_argv_p = kvm_getargv(kd, kp, argv_len);
    1857                 :            :         if (pid_argv_p == NULL)
    1858                 :            :                 errx(1, "%s", kvm_geterr(kd));
    1859                 :            : 
    1860                 :            :         /* Find and compare string. */
    1861                 :            :         start_argv_0_p = *pid_argv_p;
    1862                 :            : 
    1863                 :            :         /* Find end of argv[0] then copy and cut of str there. */
    1864                 :            :         end_argv_0_p = strchr(*pid_argv_p, ' ');
    1865                 :            :         if (end_argv_0_p == NULL)
    1866                 :            :                 /* There seems to be no space, so we have the command
    1867                 :            :                  * already in its desired form. */
    1868                 :            :                 start_argv_0_p = *pid_argv_p;
    1869                 :            :         else {
    1870                 :            :                 /* Tests indicate that this never happens, since
    1871                 :            :                  * kvm_getargv itself cuts of tailing stuff. This is
    1872                 :            :                  * not what the manpage says, however. */
    1873                 :            :                 strncpy(buf, *pid_argv_p, (end_argv_0_p - start_argv_0_p));
    1874                 :            :                 buf[(end_argv_0_p - start_argv_0_p) + 1] = '\0';
    1875                 :            :                 start_argv_0_p = buf;
    1876                 :            :         }
    1877                 :            : 
    1878                 :            :         if (stat(start_argv_0_p, &sb) != 0)
    1879                 :            :                 goto cleanup;
    1880                 :            : 
    1881                 :            :         res = (sb.st_dev == esb->st_dev && sb.st_ino == esb->st_ino);
    1882                 :            : 
    1883                 :            : cleanup:
    1884                 :            :         kvm_close(kd);
    1885                 :            : 
    1886                 :            :         return res;
    1887                 :            : }
    1888                 :            : #endif
    1889                 :            : 
    1890                 :            : #if defined(OS_Linux)
    1891                 :            : static bool
    1892                 :          0 : pid_is_child(pid_t pid, pid_t ppid)
    1893                 :            : {
    1894                 :            :         const char *ppid_str;
    1895                 :            :         pid_t proc_ppid;
    1896                 :            :         int rc;
    1897                 :            : 
    1898                 :          0 :         ppid_str = proc_status_field(pid, "PPid:");
    1899         [ #  # ]:          0 :         if (ppid_str == NULL)
    1900                 :          0 :                 return false;
    1901                 :            : 
    1902                 :          0 :         rc = parse_pid(ppid_str, &proc_ppid);
    1903         [ #  # ]:          0 :         if (rc < 0)
    1904                 :          0 :                 return false;
    1905                 :            : 
    1906                 :          0 :         return proc_ppid == ppid;
    1907                 :            : }
    1908                 :            : #elif defined(OS_Hurd)
    1909                 :            : static bool
    1910                 :            : pid_is_child(pid_t pid, pid_t ppid)
    1911                 :            : {
    1912                 :            :         struct proc_stat *ps;
    1913                 :            :         struct procinfo *pi;
    1914                 :            : 
    1915                 :            :         ps = get_proc_stat(pid, PSTAT_PROC_INFO);
    1916                 :            :         if (ps == NULL)
    1917                 :            :                 return false;
    1918                 :            : 
    1919                 :            :         pi = proc_stat_proc_info(ps);
    1920                 :            : 
    1921                 :            :         return pi->ppid == ppid;
    1922                 :            : }
    1923                 :            : #elif defined(OS_Darwin)
    1924                 :            : static bool
    1925                 :            : pid_is_child(pid_t pid, pid_t ppid)
    1926                 :            : {
    1927                 :            :         struct proc_bsdinfo info;
    1928                 :            : 
    1929                 :            :         if (proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, &info, sizeof(info)) < 0)
    1930                 :            :                 return false;
    1931                 :            : 
    1932                 :            :         return (pid_t)info.pbi_ppid == ppid;
    1933                 :            : }
    1934                 :            : #elif defined(OS_AIX)
    1935                 :            : static bool
    1936                 :            : pid_is_child(pid_t pid, pid_t ppid)
    1937                 :            : {
    1938                 :            :         struct psinfo psi;
    1939                 :            : 
    1940                 :            :         if (!proc_get_psinfo(pid, &psi))
    1941                 :            :                 return false;
    1942                 :            : 
    1943                 :            :         return (pid_t)psi.pr_ppid == ppid;
    1944                 :            : }
    1945                 :            : #elif defined(OS_HPUX)
    1946                 :            : static bool
    1947                 :            : pid_is_child(pid_t pid, pid_t ppid)
    1948                 :            : {
    1949                 :            :         struct pst_status pst;
    1950                 :            : 
    1951                 :            :         if (pstat_getproc(&pst, sizeof(pst), (size_t)0, (int)pid) < 0)
    1952                 :            :                 return false;
    1953                 :            : 
    1954                 :            :         return pst.pst_ppid == ppid;
    1955                 :            : }
    1956                 :            : #elif defined(OS_FreeBSD)
    1957                 :            : static bool
    1958                 :            : pid_is_child(pid_t pid, pid_t ppid)
    1959                 :            : {
    1960                 :            :         struct kinfo_proc kp;
    1961                 :            :         int rc, mib[4];
    1962                 :            :         size_t len;
    1963                 :            : 
    1964                 :            :         mib[0] = CTL_KERN;
    1965                 :            :         mib[1] = KERN_PROC;
    1966                 :            :         mib[2] = KERN_PROC_PID;
    1967                 :            :         mib[3] = pid;
    1968                 :            :         len = sizeof(kp);
    1969                 :            : 
    1970                 :            :         rc = sysctl(mib, 4, &kp, &len, NULL, 0);
    1971                 :            :         if (rc != 0 && errno != ESRCH)
    1972                 :            :                 return false;
    1973                 :            :         if (len == 0 || len != sizeof(kp))
    1974                 :            :                 return false;
    1975                 :            : 
    1976                 :            :         return kp.ki_ppid == ppid;
    1977                 :            : }
    1978                 :            : #elif defined(HAVE_KVM_H)
    1979                 :            : static bool
    1980                 :            : pid_is_child(pid_t pid, pid_t ppid)
    1981                 :            : {
    1982                 :            :         kvm_t *kd;
    1983                 :            :         struct kinfo_proc *kp;
    1984                 :            :         pid_t proc_ppid;
    1985                 :            :         bool res = false;
    1986                 :            : 
    1987                 :            :         kd = ssd_kvm_open();
    1988                 :            :         kp = ssd_kvm_get_procs(kd, KERN_PROC_PID, pid, NULL);
    1989                 :            :         if (kp == NULL)
    1990                 :            :                 goto cleanup;
    1991                 :            : 
    1992                 :            : #if defined(OS_FreeBSD)
    1993                 :            :         proc_ppid = kp->ki_ppid;
    1994                 :            : #elif defined(OS_OpenBSD)
    1995                 :            :         proc_ppid = kp->p_ppid;
    1996                 :            : #elif defined(OS_DragonFlyBSD)
    1997                 :            :         proc_ppid = kp->kp_ppid;
    1998                 :            : #else
    1999                 :            :         proc_ppid = kp->kp_proc.p_ppid;
    2000                 :            : #endif
    2001                 :            : 
    2002                 :            :         res = (proc_ppid == ppid);
    2003                 :            : 
    2004                 :            : cleanup:
    2005                 :            :         kvm_close(kd);
    2006                 :            : 
    2007                 :            :         return res;
    2008                 :            : }
    2009                 :            : #endif
    2010                 :            : 
    2011                 :            : #if defined(OS_Linux)
    2012                 :            : static bool
    2013                 :          0 : pid_is_user(pid_t pid, uid_t uid)
    2014                 :            : {
    2015                 :            :         struct stat sb;
    2016                 :            :         char buf[32];
    2017                 :            : 
    2018                 :          0 :         sprintf(buf, "/proc/%d", pid);
    2019         [ #  # ]:          0 :         if (stat(buf, &sb) != 0)
    2020                 :          0 :                 return false;
    2021                 :          0 :         return (sb.st_uid == uid);
    2022                 :            : }
    2023                 :            : #elif defined(OS_Hurd)
    2024                 :            : static bool
    2025                 :            : pid_is_user(pid_t pid, uid_t uid)
    2026                 :            : {
    2027                 :            :         struct proc_stat *ps;
    2028                 :            : 
    2029                 :            :         ps = get_proc_stat(pid, PSTAT_OWNER_UID);
    2030                 :            :         return ps && (uid_t)proc_stat_owner_uid(ps) == uid;
    2031                 :            : }
    2032                 :            : #elif defined(OS_Darwin)
    2033                 :            : static bool
    2034                 :            : pid_is_user(pid_t pid, uid_t uid)
    2035                 :            : {
    2036                 :            :         struct proc_bsdinfo info;
    2037                 :            : 
    2038                 :            :         if (proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, &info, sizeof(info)) < 0)
    2039                 :            :                 return false;
    2040                 :            : 
    2041                 :            :         return info.pbi_ruid == uid;
    2042                 :            : }
    2043                 :            : #elif defined(OS_AIX)
    2044                 :            : static bool
    2045                 :            : pid_is_user(pid_t pid, uid_t uid)
    2046                 :            : {
    2047                 :            :         struct psinfo psi;
    2048                 :            : 
    2049                 :            :         if (!proc_get_psinfo(pid, &psi))
    2050                 :            :                 return false;
    2051                 :            : 
    2052                 :            :         return psi.pr_uid == uid;
    2053                 :            : }
    2054                 :            : #elif defined(OS_HPUX)
    2055                 :            : static bool
    2056                 :            : pid_is_user(pid_t pid, uid_t uid)
    2057                 :            : {
    2058                 :            :         struct pst_status pst;
    2059                 :            : 
    2060                 :            :         if (pstat_getproc(&pst, sizeof(pst), (size_t)0, (int)pid) < 0)
    2061                 :            :                 return false;
    2062                 :            :         return ((uid_t)pst.pst_uid == uid);
    2063                 :            : }
    2064                 :            : #elif defined(OS_FreeBSD)
    2065                 :            : static bool
    2066                 :            : pid_is_user(pid_t pid, uid_t uid)
    2067                 :            : {
    2068                 :            :         struct kinfo_proc kp;
    2069                 :            :         int rc, mib[4];
    2070                 :            :         size_t len;
    2071                 :            : 
    2072                 :            :         mib[0] = CTL_KERN;
    2073                 :            :         mib[1] = KERN_PROC;
    2074                 :            :         mib[2] = KERN_PROC_PID;
    2075                 :            :         mib[3] = pid;
    2076                 :            :         len = sizeof(kp);
    2077                 :            : 
    2078                 :            :         rc = sysctl(mib, 4, &kp, &len, NULL, 0);
    2079                 :            :         if (rc != 0 && errno != ESRCH)
    2080                 :            :                 return false;
    2081                 :            :         if (len == 0 || len != sizeof(kp))
    2082                 :            :                 return false;
    2083                 :            : 
    2084                 :            :         return kp.ki_ruid == uid;
    2085                 :            : }
    2086                 :            : #elif defined(HAVE_KVM_H)
    2087                 :            : static bool
    2088                 :            : pid_is_user(pid_t pid, uid_t uid)
    2089                 :            : {
    2090                 :            :         kvm_t *kd;
    2091                 :            :         uid_t proc_uid;
    2092                 :            :         struct kinfo_proc *kp;
    2093                 :            :         bool res = false;
    2094                 :            : 
    2095                 :            :         kd = ssd_kvm_open();
    2096                 :            :         kp = ssd_kvm_get_procs(kd, KERN_PROC_PID, pid, NULL);
    2097                 :            :         if (kp == NULL)
    2098                 :            :                 goto cleanup;
    2099                 :            : 
    2100                 :            : #if defined(OS_FreeBSD)
    2101                 :            :         proc_uid = kp->ki_ruid;
    2102                 :            : #elif defined(OS_OpenBSD)
    2103                 :            :         proc_uid = kp->p_ruid;
    2104                 :            : #elif defined(OS_DragonFlyBSD)
    2105                 :            :         proc_uid = kp->kp_ruid;
    2106                 :            : #elif defined(OS_NetBSD)
    2107                 :            :         proc_uid = kp->kp_eproc.e_pcred.p_ruid;
    2108                 :            : #else
    2109                 :            :         if (kp->kp_proc.p_cred)
    2110                 :            :                 kvm_read(kd, (u_long)&(kp->kp_proc.p_cred->p_ruid),
    2111                 :            :                          &proc_uid, sizeof(uid_t));
    2112                 :            :         else
    2113                 :            :                 goto cleanup;
    2114                 :            : #endif
    2115                 :            : 
    2116                 :            :         res = (proc_uid == (uid_t)uid);
    2117                 :            : 
    2118                 :            : cleanup:
    2119                 :            :         kvm_close(kd);
    2120                 :            : 
    2121                 :            :         return res;
    2122                 :            : }
    2123                 :            : #endif
    2124                 :            : 
    2125                 :            : #if defined(OS_Linux)
    2126                 :            : static bool
    2127                 :          0 : pid_is_cmd(pid_t pid, const char *name)
    2128                 :            : {
    2129                 :            :         const char *comm;
    2130                 :            : 
    2131                 :          0 :         comm = proc_status_field(pid, "Name:");
    2132         [ #  # ]:          0 :         if (comm == NULL)
    2133                 :          0 :                 return false;
    2134                 :            : 
    2135                 :          0 :         return strcmp(comm, name) == 0;
    2136                 :            : }
    2137                 :            : #elif defined(OS_Hurd)
    2138                 :            : static bool
    2139                 :            : pid_is_cmd(pid_t pid, const char *name)
    2140                 :            : {
    2141                 :            :         struct proc_stat *ps;
    2142                 :            :         size_t argv0_len;
    2143                 :            :         const char *argv0;
    2144                 :            :         const char *binary_name;
    2145                 :            : 
    2146                 :            :         ps = get_proc_stat(pid, PSTAT_ARGS);
    2147                 :            :         if (ps == NULL)
    2148                 :            :                 return false;
    2149                 :            : 
    2150                 :            :         argv0 = proc_stat_args(ps);
    2151                 :            :         argv0_len = strlen(argv0) + 1;
    2152                 :            : 
    2153                 :            :         binary_name = basename(argv0);
    2154                 :            :         if (strcmp(binary_name, name) == 0)
    2155                 :            :                 return true;
    2156                 :            : 
    2157                 :            :         /* XXX: This is all kinds of ugly, but on the Hurd there's no way to
    2158                 :            :          * know the command name of a process, so we have to try to match
    2159                 :            :          * also on argv[1] for the case of an interpreted script. */
    2160                 :            :         if (proc_stat_args_len(ps) > argv0_len) {
    2161                 :            :                 const char *script_name = basename(argv0 + argv0_len);
    2162                 :            : 
    2163                 :            :                 return strcmp(script_name, name) == 0;
    2164                 :            :         }
    2165                 :            : 
    2166                 :            :         return false;
    2167                 :            : }
    2168                 :            : #elif defined(OS_AIX)
    2169                 :            : static bool
    2170                 :            : pid_is_cmd(pid_t pid, const char *name)
    2171                 :            : {
    2172                 :            :         struct psinfo psi;
    2173                 :            : 
    2174                 :            :         if (!proc_get_psinfo(pid, &psi))
    2175                 :            :                 return false;
    2176                 :            : 
    2177                 :            :         return strcmp(psi.pr_fname, name) == 0;
    2178                 :            : }
    2179                 :            : #elif defined(OS_HPUX)
    2180                 :            : static bool
    2181                 :            : pid_is_cmd(pid_t pid, const char *name)
    2182                 :            : {
    2183                 :            :         struct pst_status pst;
    2184                 :            : 
    2185                 :            :         if (pstat_getproc(&pst, sizeof(pst), (size_t)0, (int)pid) < 0)
    2186                 :            :                 return false;
    2187                 :            :         return (strcmp(pst.pst_ucomm, name) == 0);
    2188                 :            : }
    2189                 :            : #elif defined(OS_Darwin)
    2190                 :            : static bool
    2191                 :            : pid_is_cmd(pid_t pid, const char *name)
    2192                 :            : {
    2193                 :            :         char pathname[_POSIX_PATH_MAX];
    2194                 :            : 
    2195                 :            :         if (proc_pidpath(pid, pathname, sizeof(pathname)) < 0)
    2196                 :            :                 return false;
    2197                 :            : 
    2198                 :            :         return strcmp(pathname, name) == 0;
    2199                 :            : }
    2200                 :            : #elif defined(OS_FreeBSD)
    2201                 :            : static bool
    2202                 :            : pid_is_cmd(pid_t pid, const char *name)
    2203                 :            : {
    2204                 :            :         struct kinfo_proc kp;
    2205                 :            :         int rc, mib[4];
    2206                 :            :         size_t len;
    2207                 :            : 
    2208                 :            :         mib[0] = CTL_KERN;
    2209                 :            :         mib[1] = KERN_PROC;
    2210                 :            :         mib[2] = KERN_PROC_PID;
    2211                 :            :         mib[3] = pid;
    2212                 :            :         len = sizeof(kp);
    2213                 :            : 
    2214                 :            :         rc = sysctl(mib, 4, &kp, &len, NULL, 0);
    2215                 :            :         if (rc != 0 && errno != ESRCH)
    2216                 :            :                 return false;
    2217                 :            :         if (len == 0 || len != sizeof(kp))
    2218                 :            :                 return false;
    2219                 :            : 
    2220                 :            :         return strcmp(kp.ki_comm, name) == 0;
    2221                 :            : }
    2222                 :            : #elif defined(HAVE_KVM_H)
    2223                 :            : static bool
    2224                 :            : pid_is_cmd(pid_t pid, const char *name)
    2225                 :            : {
    2226                 :            :         kvm_t *kd;
    2227                 :            :         struct kinfo_proc *kp;
    2228                 :            :         char *process_name;
    2229                 :            :         bool res = false;
    2230                 :            : 
    2231                 :            :         kd = ssd_kvm_open();
    2232                 :            :         kp = ssd_kvm_get_procs(kd, KERN_PROC_PID, pid, NULL);
    2233                 :            :         if (kp == NULL)
    2234                 :            :                 goto cleanup;
    2235                 :            : 
    2236                 :            : #if defined(OS_FreeBSD)
    2237                 :            :         process_name = kp->ki_comm;
    2238                 :            : #elif defined(OS_OpenBSD)
    2239                 :            :         process_name = kp->p_comm;
    2240                 :            : #elif defined(OS_DragonFlyBSD)
    2241                 :            :         process_name = kp->kp_comm;
    2242                 :            : #else
    2243                 :            :         process_name = kp->kp_proc.p_comm;
    2244                 :            : #endif
    2245                 :            : 
    2246                 :            :         res = (strcmp(name, process_name) == 0);
    2247                 :            : 
    2248                 :            : cleanup:
    2249                 :            :         kvm_close(kd);
    2250                 :            : 
    2251                 :            :         return res;
    2252                 :            : }
    2253                 :            : #endif
    2254                 :            : 
    2255                 :            : #if defined(OS_Hurd)
    2256                 :            : static bool
    2257                 :            : pid_is_running(pid_t pid)
    2258                 :            : {
    2259                 :            :         return get_proc_stat(pid, 0) != NULL;
    2260                 :            : }
    2261                 :            : #else /* !OS_Hurd */
    2262                 :            : static bool
    2263                 :          0 : pid_is_running(pid_t pid)
    2264                 :            : {
    2265   [ #  #  #  # ]:          0 :         if (kill(pid, 0) == 0 || errno == EPERM)
    2266                 :          0 :                 return true;
    2267         [ #  # ]:          0 :         else if (errno == ESRCH)
    2268                 :          0 :                 return false;
    2269                 :            :         else
    2270                 :          0 :                 fatale("error checking pid %u status", pid);
    2271                 :            : }
    2272                 :            : #endif
    2273                 :            : 
    2274                 :            : static enum status_code
    2275                 :          0 : pid_check(pid_t pid)
    2276                 :            : {
    2277   [ #  #  #  # ]:          0 :         if (execname && !pid_is_exec(pid, &exec_stat))
    2278                 :          0 :                 return STATUS_DEAD;
    2279   [ #  #  #  # ]:          0 :         if (match_ppid > 0 && !pid_is_child(pid, match_ppid))
    2280                 :          0 :                 return STATUS_DEAD;
    2281   [ #  #  #  # ]:          0 :         if (userspec && !pid_is_user(pid, user_id))
    2282                 :          0 :                 return STATUS_DEAD;
    2283   [ #  #  #  # ]:          0 :         if (cmdname && !pid_is_cmd(pid, cmdname))
    2284                 :          0 :                 return STATUS_DEAD;
    2285   [ #  #  #  # ]:          0 :         if (action != ACTION_STOP && !pid_is_running(pid))
    2286                 :          0 :                 return STATUS_DEAD;
    2287                 :            : 
    2288                 :          0 :         pid_list_push(&found, pid);
    2289                 :            : 
    2290                 :          0 :         return STATUS_OK;
    2291                 :            : }
    2292                 :            : 
    2293                 :            : static enum status_code
    2294                 :          0 : do_pidfile(const char *name)
    2295                 :            : {
    2296                 :            :         FILE *f;
    2297                 :            :         static pid_t pid = 0;
    2298                 :            : 
    2299         [ #  # ]:          0 :         if (pid)
    2300                 :          0 :                 return pid_check(pid);
    2301                 :            : 
    2302                 :          0 :         f = fopen(name, "r");
    2303         [ #  # ]:          0 :         if (f) {
    2304                 :            :                 enum status_code pid_status;
    2305                 :            : 
    2306                 :            :                 /* If we are only matching on the pidfile, and it is owned by
    2307                 :            :                  * a non-root user, then this is a security risk, and the
    2308                 :            :                  * contents cannot be trusted, because the daemon might have
    2309                 :            :                  * been compromised.
    2310                 :            :                  *
    2311                 :            :                  * If the pidfile is world-writable we refuse to parse it.
    2312                 :            :                  *
    2313                 :            :                  * If we got /dev/null specified as the pidfile, we ignore the
    2314                 :            :                  * checks, as this is being used to run processes no matter
    2315                 :            :                  * what. */
    2316         [ #  # ]:          0 :                 if (strcmp(name, "/dev/null") != 0) {
    2317                 :            :                         struct stat st;
    2318                 :          0 :                         int fd = fileno(f);
    2319                 :            : 
    2320         [ #  # ]:          0 :                         if (fstat(fd, &st) < 0)
    2321                 :          0 :                                 fatale("cannot stat pidfile %s", name);
    2322                 :            : 
    2323   [ #  #  #  # ]:          0 :                         if (match_mode == MATCH_PIDFILE &&
    2324   [ #  #  #  # ]:          0 :                             ((st.st_uid != getuid() && st.st_uid != 0) ||
    2325         [ #  # ]:          0 :                              (st.st_gid != getgid() && st.st_gid != 0)))
    2326                 :          0 :                                 fatal("matching only on non-root pidfile %s is insecure", name);
    2327         [ #  # ]:          0 :                         if (st.st_mode & 0002)
    2328                 :          0 :                                 fatal("matching on world-writable pidfile %s is insecure", name);
    2329                 :            : 
    2330                 :            :                 }
    2331                 :            : 
    2332         [ #  # ]:          0 :                 if (fscanf(f, "%d", &pid) == 1)
    2333                 :          0 :                         pid_status = pid_check(pid);
    2334                 :            :                 else
    2335                 :          0 :                         pid_status = STATUS_UNKNOWN;
    2336                 :          0 :                 fclose(f);
    2337                 :            : 
    2338         [ #  # ]:          0 :                 if (pid_status == STATUS_DEAD)
    2339                 :          0 :                         return STATUS_DEAD_PIDFILE;
    2340                 :            :                 else
    2341                 :          0 :                         return pid_status;
    2342         [ #  # ]:          0 :         } else if (errno == ENOENT)
    2343                 :          0 :                 return STATUS_DEAD;
    2344                 :            :         else
    2345                 :          0 :                 fatale("unable to open pidfile %s", name);
    2346                 :            : }
    2347                 :            : 
    2348                 :            : #if defined(OS_Linux) || defined(OS_Solaris) || defined(OS_AIX)
    2349                 :            : static enum status_code
    2350                 :          0 : do_procinit(void)
    2351                 :            : {
    2352                 :            :         DIR *procdir;
    2353                 :            :         struct dirent *entry;
    2354                 :            :         int foundany;
    2355                 :            :         pid_t pid;
    2356                 :          0 :         enum status_code prog_status = STATUS_DEAD;
    2357                 :            : 
    2358                 :          0 :         procdir = opendir("/proc");
    2359         [ #  # ]:          0 :         if (!procdir)
    2360                 :          0 :                 fatale("unable to opendir /proc");
    2361                 :            : 
    2362                 :          0 :         foundany = 0;
    2363         [ #  # ]:          0 :         while ((entry = readdir(procdir)) != NULL) {
    2364                 :            :                 enum status_code pid_status;
    2365                 :            : 
    2366         [ #  # ]:          0 :                 if (sscanf(entry->d_name, "%d", &pid) != 1)
    2367                 :          0 :                         continue;
    2368                 :          0 :                 foundany++;
    2369                 :            : 
    2370                 :          0 :                 pid_status = pid_check(pid);
    2371         [ #  # ]:          0 :                 if (pid_status < prog_status)
    2372                 :          0 :                         prog_status = pid_status;
    2373                 :            :         }
    2374                 :          0 :         closedir(procdir);
    2375         [ #  # ]:          0 :         if (foundany == 0)
    2376                 :          0 :                 fatal("nothing in /proc - not mounted?");
    2377                 :            : 
    2378                 :          0 :         return prog_status;
    2379                 :            : }
    2380                 :            : #elif defined(OS_Hurd)
    2381                 :            : static int
    2382                 :            : check_proc_stat(struct proc_stat *ps)
    2383                 :            : {
    2384                 :            :         pid_check(proc_stat_pid(ps));
    2385                 :            :         return 0;
    2386                 :            : }
    2387                 :            : 
    2388                 :            : static enum status_code
    2389                 :            : do_procinit(void)
    2390                 :            : {
    2391                 :            :         if (!procset)
    2392                 :            :                 init_procset();
    2393                 :            : 
    2394                 :            :         proc_stat_list_for_each(procset, check_proc_stat);
    2395                 :            : 
    2396                 :            :         if (found)
    2397                 :            :                 return STATUS_OK;
    2398                 :            :         else
    2399                 :            :                 return STATUS_DEAD;
    2400                 :            : }
    2401                 :            : #elif defined(OS_Darwin)
    2402                 :            : static enum status_code
    2403                 :            : do_procinit(void)
    2404                 :            : {
    2405                 :            :         pid_t *pid_buf;
    2406                 :            :         int i, npids, pid_bufsize;
    2407                 :            :         enum status_code prog_status = STATUS_DEAD;
    2408                 :            : 
    2409                 :            :         npids = proc_listallpids(NULL, 0);
    2410                 :            :         if (npids == 0)
    2411                 :            :                 return STATUS_UNKNOWN;
    2412                 :            : 
    2413                 :            :         /* Try to avoid sudden changes in number of PIDs. */
    2414                 :            :         npids += 4096;
    2415                 :            :         pid_bufsize = sizeof(pid_t) * npids;
    2416                 :            :         pid_buf = xmalloc(pid_bufsize);
    2417                 :            : 
    2418                 :            :         npids = proc_listallpids(pid_buf, pid_bufsize);
    2419                 :            :         if (npids == 0)
    2420                 :            :                 return STATUS_UNKNOWN;
    2421                 :            : 
    2422                 :            :         for (i = 0; i < npids; i++) {
    2423                 :            :                 enum status_code pid_status;
    2424                 :            : 
    2425                 :            :                 pid_status = pid_check(pid_buf[i]);
    2426                 :            :                 if (pid_status < prog_status)
    2427                 :            :                         prog_status = pid_status;
    2428                 :            :         }
    2429                 :            : 
    2430                 :            :         free(pid_buf);
    2431                 :            : 
    2432                 :            :         return prog_status;
    2433                 :            : }
    2434                 :            : #elif defined(OS_HPUX)
    2435                 :            : static enum status_code
    2436                 :            : do_procinit(void)
    2437                 :            : {
    2438                 :            :         struct pst_status pst[10];
    2439                 :            :         int i, count;
    2440                 :            :         int idx = 0;
    2441                 :            :         enum status_code prog_status = STATUS_DEAD;
    2442                 :            : 
    2443                 :            :         while ((count = pstat_getproc(pst, sizeof(pst[0]), 10, idx)) > 0) {
    2444                 :            :                 enum status_code pid_status;
    2445                 :            : 
    2446                 :            :                 for (i = 0; i < count; i++) {
    2447                 :            :                         pid_status = pid_check(pst[i].pst_pid);
    2448                 :            :                         if (pid_status < prog_status)
    2449                 :            :                                 prog_status = pid_status;
    2450                 :            :                 }
    2451                 :            :                 idx = pst[count - 1].pst_idx + 1;
    2452                 :            :         }
    2453                 :            : 
    2454                 :            :         return prog_status;
    2455                 :            : }
    2456                 :            : #elif defined(OS_FreeBSD)
    2457                 :            : static enum status_code
    2458                 :            : do_procinit(void)
    2459                 :            : {
    2460                 :            :         struct kinfo_proc *kp;
    2461                 :            :         int rc, mib[3];
    2462                 :            :         size_t len = 0;
    2463                 :            :         int nentries, i;
    2464                 :            :         enum status_code prog_status = STATUS_DEAD;
    2465                 :            : 
    2466                 :            :         mib[0] = CTL_KERN;
    2467                 :            :         mib[1] = KERN_PROC;
    2468                 :            :         mib[2] = KERN_PROC_PROC;
    2469                 :            : 
    2470                 :            :         rc = sysctl(mib, 3, NULL, &len, NULL, 0);
    2471                 :            :         if (rc != 0 && errno != ESRCH)
    2472                 :            :                 return STATUS_UNKNOWN;
    2473                 :            :         if (len == 0)
    2474                 :            :                 return STATUS_UNKNOWN;
    2475                 :            : 
    2476                 :            :         kp = xmalloc(len);
    2477                 :            :         rc = sysctl(mib, 3, kp, &len, NULL, 0);
    2478                 :            :         if (rc != 0 && errno != ESRCH)
    2479                 :            :                 return STATUS_UNKNOWN;
    2480                 :            :         if (len == 0)
    2481                 :            :                 return STATUS_UNKNOWN;
    2482                 :            :         nentries = len / sizeof(*kp);
    2483                 :            : 
    2484                 :            :         for (i = 0; i < nentries; i++) {
    2485                 :            :                 enum status_code pid_status;
    2486                 :            : 
    2487                 :            :                 pid_status = pid_check(kp[i].ki_pid);
    2488                 :            :                 if (pid_status < prog_status)
    2489                 :            :                         prog_status = pid_status;
    2490                 :            :         }
    2491                 :            : 
    2492                 :            :         free(kp);
    2493                 :            : 
    2494                 :            :         return prog_status;
    2495                 :            : }
    2496                 :            : #elif defined(HAVE_KVM_H)
    2497                 :            : static enum status_code
    2498                 :            : do_procinit(void)
    2499                 :            : {
    2500                 :            :         kvm_t *kd;
    2501                 :            :         int nentries, i;
    2502                 :            :         struct kinfo_proc *kp;
    2503                 :            :         enum status_code prog_status = STATUS_DEAD;
    2504                 :            : 
    2505                 :            :         kd = ssd_kvm_open();
    2506                 :            :         kp = ssd_kvm_get_procs(kd, KERN_PROC_ALL, 0, &nentries);
    2507                 :            : 
    2508                 :            :         for (i = 0; i < nentries; i++) {
    2509                 :            :                 enum status_code pid_status;
    2510                 :            :                 pid_t pid;
    2511                 :            : 
    2512                 :            : #if defined(OS_FreeBSD)
    2513                 :            :                 pid = kp[i].ki_pid;
    2514                 :            : #elif defined(OS_OpenBSD)
    2515                 :            :                 pid = kp[i].p_pid;
    2516                 :            : #elif defined(OS_DragonFlyBSD)
    2517                 :            :                 pid = kp[i].kp_pid;
    2518                 :            : #else
    2519                 :            :                 pid = kp[i].kp_proc.p_pid;
    2520                 :            : #endif
    2521                 :            : 
    2522                 :            :                 pid_status = pid_check(pid);
    2523                 :            :                 if (pid_status < prog_status)
    2524                 :            :                         prog_status = pid_status;
    2525                 :            :         }
    2526                 :            : 
    2527                 :            :         kvm_close(kd);
    2528                 :            : 
    2529                 :            :         return prog_status;
    2530                 :            : }
    2531                 :            : #endif
    2532                 :            : 
    2533                 :            : static enum status_code
    2534                 :          0 : do_findprocs(void)
    2535                 :            : {
    2536                 :          0 :         pid_list_free(&found);
    2537                 :            : 
    2538         [ #  # ]:          0 :         if (match_pid > 0)
    2539                 :          0 :                 return pid_check(match_pid);
    2540         [ #  # ]:          0 :         else if (pidfile)
    2541                 :          0 :                 return do_pidfile(pidfile);
    2542                 :            :         else
    2543                 :          0 :                 return do_procinit();
    2544                 :            : }
    2545                 :            : 
    2546                 :            : static int
    2547                 :          0 : do_start(int argc, char **argv)
    2548                 :            : {
    2549                 :          0 :         int devnull_fd = -1;
    2550                 :          0 :         int output_fd = -1;
    2551                 :            :         gid_t rgid;
    2552                 :            :         uid_t ruid;
    2553                 :            : 
    2554                 :          0 :         do_findprocs();
    2555                 :            : 
    2556         [ #  # ]:          0 :         if (found) {
    2557         [ #  # ]:          0 :                 info("%s already running.\n", execname ? execname : "process");
    2558                 :          0 :                 return exitnodo;
    2559                 :            :         }
    2560   [ #  #  #  # ]:          0 :         if (testmode && quietmode <= 0) {
    2561                 :          0 :                 printf("Would start %s ", startas);
    2562         [ #  # ]:          0 :                 while (argc-- > 0)
    2563                 :          0 :                         printf("%s ", *argv++);
    2564         [ #  # ]:          0 :                 if (changeuser != NULL) {
    2565                 :          0 :                         printf(" (as user %s[%d]", changeuser, runas_uid);
    2566         [ #  # ]:          0 :                         if (changegroup != NULL)
    2567                 :          0 :                                 printf(", and group %s[%d])", changegroup, runas_gid);
    2568                 :            :                         else
    2569                 :          0 :                                 printf(")");
    2570                 :            :                 }
    2571         [ #  # ]:          0 :                 if (changeroot != NULL)
    2572                 :          0 :                         printf(" in directory %s", changeroot);
    2573         [ #  # ]:          0 :                 if (nicelevel)
    2574                 :          0 :                         printf(", and add %i to the priority", nicelevel);
    2575         [ #  # ]:          0 :                 if (proc_sched)
    2576                 :          0 :                         printf(", with scheduling policy %s with priority %i",
    2577                 :          0 :                                proc_sched->policy_name, proc_sched->priority);
    2578         [ #  # ]:          0 :                 if (io_sched)
    2579                 :          0 :                         printf(", with IO scheduling class %s with priority %i",
    2580                 :          0 :                                io_sched->policy_name, io_sched->priority);
    2581                 :          0 :                 printf(".\n");
    2582                 :            :         }
    2583         [ #  # ]:          0 :         if (testmode)
    2584                 :          0 :                 return 0;
    2585                 :          0 :         debug("Starting %s...\n", startas);
    2586                 :          0 :         *--argv = startas;
    2587         [ #  # ]:          0 :         if (umask_value >= 0)
    2588                 :          0 :                 umask(umask_value);
    2589         [ #  # ]:          0 :         if (background)
    2590                 :            :                 /* Ok, we need to detach this process. */
    2591                 :          0 :                 daemonize();
    2592   [ #  #  #  # ]:          0 :         else if (mpidfile && pidfile != NULL)
    2593                 :            :                 /* User wants _us_ to make the pidfile, but detach themself! */
    2594                 :          0 :                 write_pidfile(pidfile, getpid());
    2595   [ #  #  #  # ]:          0 :         if (background && close_io) {
    2596                 :          0 :                 devnull_fd = open("/dev/null", O_RDONLY);
    2597         [ #  # ]:          0 :                 if (devnull_fd < 0)
    2598                 :          0 :                         fatale("unable to open '%s'", "/dev/null");
    2599                 :            :         }
    2600   [ #  #  #  # ]:          0 :         if (background && output_io) {
    2601                 :          0 :                 output_fd = open(output_io, O_CREAT | O_WRONLY | O_APPEND, 0664);
    2602         [ #  # ]:          0 :                 if (output_fd < 0)
    2603                 :          0 :                         fatale("unable to open '%s'", output_io);
    2604                 :            :         }
    2605         [ #  # ]:          0 :         if (nicelevel) {
    2606                 :          0 :                 errno = 0;
    2607   [ #  #  #  # ]:          0 :                 if ((nice(nicelevel) == -1) && (errno != 0))
    2608                 :          0 :                         fatale("unable to alter nice level by %i", nicelevel);
    2609                 :            :         }
    2610         [ #  # ]:          0 :         if (proc_sched)
    2611                 :          0 :                 set_proc_schedule(proc_sched);
    2612         [ #  # ]:          0 :         if (io_sched)
    2613                 :          0 :                 set_io_schedule(io_sched);
    2614         [ #  # ]:          0 :         if (changeroot != NULL) {
    2615         [ #  # ]:          0 :                 if (chdir(changeroot) < 0)
    2616                 :          0 :                         fatale("unable to chdir() to %s", changeroot);
    2617         [ #  # ]:          0 :                 if (chroot(changeroot) < 0)
    2618                 :          0 :                         fatale("unable to chroot() to %s", changeroot);
    2619                 :            :         }
    2620         [ #  # ]:          0 :         if (chdir(changedir) < 0)
    2621                 :          0 :                 fatale("unable to chdir() to %s", changedir);
    2622                 :            : 
    2623                 :          0 :         rgid = getgid();
    2624                 :          0 :         ruid = getuid();
    2625         [ #  # ]:          0 :         if (changegroup != NULL) {
    2626         [ #  # ]:          0 :                 if (rgid != (gid_t)runas_gid)
    2627         [ #  # ]:          0 :                         if (setgid(runas_gid))
    2628                 :          0 :                                 fatale("unable to set gid to %d", runas_gid);
    2629                 :            :         }
    2630         [ #  # ]:          0 :         if (changeuser != NULL) {
    2631                 :            :                 /* We assume that if our real user and group are the same as
    2632                 :            :                  * the ones we should switch to, the supplementary groups
    2633                 :            :                  * will be already in place. */
    2634   [ #  #  #  # ]:          0 :                 if (rgid != (gid_t)runas_gid || ruid != (uid_t)runas_uid)
    2635         [ #  # ]:          0 :                         if (initgroups(changeuser, runas_gid))
    2636                 :          0 :                                 fatale("unable to set initgroups() with gid %d",
    2637                 :            :                                       runas_gid);
    2638                 :            : 
    2639         [ #  # ]:          0 :                 if (ruid != (uid_t)runas_uid)
    2640         [ #  # ]:          0 :                         if (setuid(runas_uid))
    2641                 :          0 :                                 fatale("unable to set uid to %s", changeuser);
    2642                 :            :         }
    2643                 :            : 
    2644   [ #  #  #  # ]:          0 :         if (background && output_fd >= 0) {
    2645                 :          0 :                 dup2(output_fd, 1); /* stdout */
    2646                 :          0 :                 dup2(output_fd, 2); /* stderr */
    2647                 :            :         }
    2648   [ #  #  #  # ]:          0 :         if (background && close_io) {
    2649                 :            :                 int i;
    2650                 :            : 
    2651                 :          0 :                 dup2(devnull_fd, 0); /* stdin */
    2652                 :            : 
    2653                 :            :                  /* Now close all extra fds. */
    2654         [ #  # ]:          0 :                 for (i = get_open_fd_max() - 1; i >= 3; --i)
    2655                 :          0 :                         close(i);
    2656                 :            :         }
    2657                 :          0 :         execv(startas, argv);
    2658                 :          0 :         fatale("unable to start %s", startas);
    2659                 :            : }
    2660                 :            : 
    2661                 :            : static void
    2662                 :          0 : do_stop(int sig_num, int *n_killed, int *n_notkilled)
    2663                 :            : {
    2664                 :            :         struct pid_list *p;
    2665                 :            : 
    2666                 :          0 :         do_findprocs();
    2667                 :            : 
    2668                 :          0 :         *n_killed = 0;
    2669                 :          0 :         *n_notkilled = 0;
    2670                 :            : 
    2671         [ #  # ]:          0 :         if (!found)
    2672                 :          0 :                 return;
    2673                 :            : 
    2674                 :          0 :         pid_list_free(&killed);
    2675                 :            : 
    2676         [ #  # ]:          0 :         for (p = found; p; p = p->next) {
    2677         [ #  # ]:          0 :                 if (testmode) {
    2678                 :          0 :                         info("Would send signal %d to %d.\n", sig_num, p->pid);
    2679                 :          0 :                         (*n_killed)++;
    2680         [ #  # ]:          0 :                 } else if (kill(p->pid, sig_num) == 0) {
    2681                 :          0 :                         pid_list_push(&killed, p->pid);
    2682                 :          0 :                         (*n_killed)++;
    2683                 :            :                 } else {
    2684         [ #  # ]:          0 :                         if (sig_num)
    2685                 :          0 :                                 warning("failed to kill %d: %s\n",
    2686                 :          0 :                                         p->pid, strerror(errno));
    2687                 :          0 :                         (*n_notkilled)++;
    2688                 :            :                 }
    2689                 :            :         }
    2690                 :            : }
    2691                 :            : 
    2692                 :            : static void
    2693                 :          0 : do_stop_summary(int retry_nr)
    2694                 :            : {
    2695                 :            :         struct pid_list *p;
    2696                 :            : 
    2697   [ #  #  #  # ]:          0 :         if (quietmode >= 0 || !killed)
    2698                 :          0 :                 return;
    2699                 :            : 
    2700                 :          0 :         printf("Stopped %s (pid", what_stop);
    2701         [ #  # ]:          0 :         for (p = killed; p; p = p->next)
    2702                 :          0 :                 printf(" %d", p->pid);
    2703                 :          0 :         putchar(')');
    2704         [ #  # ]:          0 :         if (retry_nr > 0)
    2705                 :          0 :                 printf(", retry #%d", retry_nr);
    2706                 :          0 :         printf(".\n");
    2707                 :            : }
    2708                 :            : 
    2709                 :            : static void DPKG_ATTR_PRINTF(1)
    2710                 :          0 : set_what_stop(const char *format, ...)
    2711                 :            : {
    2712                 :            :         va_list arglist;
    2713                 :            :         int rc;
    2714                 :            : 
    2715                 :          0 :         va_start(arglist, format);
    2716                 :          0 :         rc = vasprintf(&what_stop, format, arglist);
    2717                 :          0 :         va_end(arglist);
    2718                 :            : 
    2719         [ #  # ]:          0 :         if (rc < 0)
    2720                 :          0 :                 fatale("cannot allocate formatted string");
    2721                 :          0 : }
    2722                 :            : 
    2723                 :            : /*
    2724                 :            :  * We want to keep polling for the processes, to see if they've exited, or
    2725                 :            :  * until the timeout expires.
    2726                 :            :  *
    2727                 :            :  * This is a somewhat complicated algorithm to try to ensure that we notice
    2728                 :            :  * reasonably quickly when all the processes have exited, but don't spend
    2729                 :            :  * too much CPU time polling. In particular, on a fast machine with
    2730                 :            :  * quick-exiting daemons we don't want to delay system shutdown too much,
    2731                 :            :  * whereas on a slow one, or where processes are taking some time to exit,
    2732                 :            :  * we want to increase the polling interval.
    2733                 :            :  *
    2734                 :            :  * The algorithm is as follows: we measure the elapsed time it takes to do
    2735                 :            :  * one poll(), and wait a multiple of this time for the next poll. However,
    2736                 :            :  * if that would put us past the end of the timeout period we wait only as
    2737                 :            :  * long as the timeout period, but in any case we always wait at least
    2738                 :            :  * MIN_POLL_INTERVAL (20ms). The multiple (‘ratio’) starts out as 2, and
    2739                 :            :  * increases by 1 for each poll to a maximum of 10; so we use up to between
    2740                 :            :  * 30% and 10% of the machine's resources (assuming a few reasonable things
    2741                 :            :  * about system performance).
    2742                 :            :  */
    2743                 :            : static bool
    2744                 :          0 : do_stop_timeout(int timeout, int *n_killed, int *n_notkilled)
    2745                 :            : {
    2746                 :            :         struct timespec stopat, before, after, interval, maxinterval;
    2747                 :            :         int rc, ratio;
    2748                 :            : 
    2749                 :          0 :         timespec_gettime(&stopat);
    2750                 :          0 :         stopat.tv_sec += timeout;
    2751                 :          0 :         ratio = 1;
    2752                 :            :         for (;;) {
    2753                 :          0 :                 timespec_gettime(&before);
    2754   [ #  #  #  # ]:          0 :                 if (timespec_cmp(&before, &stopat, >))
    2755                 :          0 :                         return false;
    2756                 :            : 
    2757                 :          0 :                 do_stop(0, n_killed, n_notkilled);
    2758         [ #  # ]:          0 :                 if (!*n_killed)
    2759                 :          0 :                         return true;
    2760                 :            : 
    2761                 :          0 :                 timespec_gettime(&after);
    2762                 :            : 
    2763   [ #  #  #  # ]:          0 :                 if (!timespec_cmp(&after, &stopat, <))
    2764                 :          0 :                         return false;
    2765                 :            : 
    2766         [ #  # ]:          0 :                 if (ratio < 10)
    2767                 :          0 :                         ratio++;
    2768                 :            : 
    2769                 :          0 :                 timespec_sub(&stopat, &after, &maxinterval);
    2770                 :          0 :                 timespec_sub(&after, &before, &interval);
    2771                 :          0 :                 timespec_mul(&interval, ratio);
    2772                 :            : 
    2773   [ #  #  #  # ]:          0 :                 if (interval.tv_sec < 0 || interval.tv_nsec < 0)
    2774                 :          0 :                         interval.tv_sec = interval.tv_nsec = 0;
    2775                 :            : 
    2776   [ #  #  #  # ]:          0 :                 if (timespec_cmp(&interval, &maxinterval, >))
    2777                 :          0 :                         interval = maxinterval;
    2778                 :            : 
    2779         [ #  # ]:          0 :                 if (interval.tv_sec == 0 &&
    2780         [ #  # ]:          0 :                     interval.tv_nsec <= MIN_POLL_INTERVAL)
    2781                 :          0 :                         interval.tv_nsec = MIN_POLL_INTERVAL;
    2782                 :            : 
    2783                 :          0 :                 rc = pselect(0, NULL, NULL, NULL, &interval, NULL);
    2784   [ #  #  #  # ]:          0 :                 if (rc < 0 && errno != EINTR)
    2785                 :          0 :                         fatale("select() failed for pause");
    2786                 :            :         }
    2787                 :            : }
    2788                 :            : 
    2789                 :            : static int
    2790                 :          0 : finish_stop_schedule(bool anykilled)
    2791                 :            : {
    2792   [ #  #  #  #  :          0 :         if (rpidfile && pidfile && !testmode)
                   #  # ]
    2793                 :          0 :                 remove_pidfile(pidfile);
    2794                 :            : 
    2795         [ #  # ]:          0 :         if (anykilled)
    2796                 :          0 :                 return 0;
    2797                 :            : 
    2798                 :          0 :         info("No %s found running; none killed.\n", what_stop);
    2799                 :            : 
    2800                 :          0 :         return exitnodo;
    2801                 :            : }
    2802                 :            : 
    2803                 :            : static int
    2804                 :          0 : run_stop_schedule(void)
    2805                 :            : {
    2806                 :            :         int position, n_killed, n_notkilled, value, retry_nr;
    2807                 :            :         bool anykilled;
    2808                 :            : 
    2809         [ #  # ]:          0 :         if (testmode) {
    2810         [ #  # ]:          0 :                 if (schedule != NULL) {
    2811                 :          0 :                         info("Ignoring --retry in test mode\n");
    2812                 :          0 :                         schedule = NULL;
    2813                 :            :                 }
    2814                 :            :         }
    2815                 :            : 
    2816         [ #  # ]:          0 :         if (cmdname)
    2817                 :          0 :                 set_what_stop("%s", cmdname);
    2818         [ #  # ]:          0 :         else if (execname)
    2819                 :          0 :                 set_what_stop("%s", execname);
    2820         [ #  # ]:          0 :         else if (pidfile)
    2821                 :          0 :                 set_what_stop("process in pidfile '%s'", pidfile);
    2822         [ #  # ]:          0 :         else if (match_pid > 0)
    2823                 :          0 :                 set_what_stop("process with pid %d", match_pid);
    2824         [ #  # ]:          0 :         else if (match_ppid > 0)
    2825                 :          0 :                 set_what_stop("process(es) with parent pid %d", match_ppid);
    2826         [ #  # ]:          0 :         else if (userspec)
    2827                 :          0 :                 set_what_stop("process(es) owned by '%s'", userspec);
    2828                 :            :         else
    2829                 :          0 :                 BUG("no match option, please report");
    2830                 :            : 
    2831                 :          0 :         anykilled = false;
    2832                 :          0 :         retry_nr = 0;
    2833                 :            : 
    2834         [ #  # ]:          0 :         if (schedule == NULL) {
    2835                 :          0 :                 do_stop(signal_nr, &n_killed, &n_notkilled);
    2836                 :          0 :                 do_stop_summary(0);
    2837         [ #  # ]:          0 :                 if (n_notkilled > 0)
    2838                 :          0 :                         info("%d pids were not killed\n", n_notkilled);
    2839         [ #  # ]:          0 :                 if (n_killed)
    2840                 :          0 :                         anykilled = true;
    2841                 :          0 :                 return finish_stop_schedule(anykilled);
    2842                 :            :         }
    2843                 :            : 
    2844         [ #  # ]:          0 :         for (position = 0; position < schedule_length; position++) {
    2845                 :          0 :         reposition:
    2846                 :          0 :                 value = schedule[position].value;
    2847                 :          0 :                 n_notkilled = 0;
    2848                 :            : 
    2849   [ #  #  #  # ]:          0 :                 switch (schedule[position].type) {
    2850                 :          0 :                 case sched_goto:
    2851                 :          0 :                         position = value;
    2852                 :          0 :                         goto reposition;
    2853                 :          0 :                 case sched_signal:
    2854                 :          0 :                         do_stop(value, &n_killed, &n_notkilled);
    2855                 :          0 :                         do_stop_summary(retry_nr++);
    2856         [ #  # ]:          0 :                         if (!n_killed)
    2857                 :          0 :                                 return finish_stop_schedule(anykilled);
    2858                 :            :                         else
    2859                 :          0 :                                 anykilled = true;
    2860                 :          0 :                         continue;
    2861                 :          0 :                 case sched_timeout:
    2862         [ #  # ]:          0 :                         if (do_stop_timeout(value, &n_killed, &n_notkilled))
    2863                 :          0 :                                 return finish_stop_schedule(anykilled);
    2864                 :            :                         else
    2865                 :          0 :                                 continue;
    2866                 :          0 :                 default:
    2867                 :          0 :                         BUG("schedule[%d].type value %d is not valid",
    2868                 :            :                             position, schedule[position].type);
    2869                 :            :                 }
    2870                 :            :         }
    2871                 :            : 
    2872                 :          0 :         info("Program %s, %d process(es), refused to die.\n",
    2873                 :            :              what_stop, n_killed);
    2874                 :            : 
    2875                 :          0 :         return 2;
    2876                 :            : }
    2877                 :            : 
    2878                 :            : int
    2879                 :          0 : main(int argc, char **argv)
    2880                 :            : {
    2881                 :          0 :         progname = argv[0];
    2882                 :            : 
    2883                 :          0 :         parse_options(argc, argv);
    2884                 :          0 :         setup_options();
    2885                 :            : 
    2886                 :          0 :         argc -= optind;
    2887                 :          0 :         argv += optind;
    2888                 :            : 
    2889         [ #  # ]:          0 :         if (action == ACTION_START)
    2890                 :          0 :                 return do_start(argc, argv);
    2891         [ #  # ]:          0 :         else if (action == ACTION_STOP)
    2892                 :          0 :                 return run_stop_schedule();
    2893         [ #  # ]:          0 :         else if (action == ACTION_STATUS)
    2894                 :          0 :                 return do_findprocs();
    2895                 :            : 
    2896                 :          0 :         return 0;
    2897                 :            : }

Generated by: LCOV version 1.16