diff options
Diffstat (limited to 'src/start-stop-daemon.c')
-rw-r--r-- | src/start-stop-daemon.c | 1793 |
1 files changed, 862 insertions, 931 deletions
diff --git a/src/start-stop-daemon.c b/src/start-stop-daemon.c index 499543b9..384b72c6 100644 --- a/src/start-stop-daemon.c +++ b/src/start-stop-daemon.c @@ -46,16 +46,16 @@ static struct pam_conv conv = { NULL, NULL} ; typedef struct schedulelist { - enum - { - schedule_timeout, - schedule_signal, - schedule_goto, - schedule_forever - } type; - int value; - struct schedulelist *gotolist; - struct schedulelist *next; + enum + { + schedule_timeout, + schedule_signal, + schedule_goto, + schedule_forever + } type; + int value; + struct schedulelist *gotolist; + struct schedulelist *next; } schedulelist_t; static schedulelist_t *schedule; @@ -67,990 +67,921 @@ extern char **environ; static void free_schedulelist (schedulelist_t **list) { - schedulelist_t *here; - schedulelist_t *next; + schedulelist_t *here; + schedulelist_t *next; - for (here = *list; here; here = next) - { - next = here->next; - free (here); - } + for (here = *list; here; here = next) { + next = here->next; + free (here); + } - *list = NULL; + *list = NULL; } static void cleanup (void) { - if (changeuser) - free (changeuser); + if (changeuser) + free (changeuser); - if (schedule) - free_schedulelist (&schedule); + if (schedule) + free_schedulelist (&schedule); - if (newenv) - rc_strlist_free (newenv); + if (newenv) + rc_strlist_free (newenv); } static int parse_signal (const char *sig) { - typedef struct signalpair - { - const char *name; - int signal; - } signalpair_t; - - static const signalpair_t signallist[] = { - { "ABRT", SIGABRT }, - { "ALRM", SIGALRM }, - { "FPE", SIGFPE }, - { "HUP", SIGHUP }, - { "ILL", SIGILL }, - { "INT", SIGINT }, - { "KILL", SIGKILL }, - { "PIPE", SIGPIPE }, - { "QUIT", SIGQUIT }, - { "SEGV", SIGSEGV }, - { "TERM", SIGTERM }, - { "USR1", SIGUSR1 }, - { "USR2", SIGUSR2 }, - { "CHLD", SIGCHLD }, - { "CONT", SIGCONT }, - { "STOP", SIGSTOP }, - { "TSTP", SIGTSTP }, - { "TTIN", SIGTTIN }, - { "TTOU", SIGTTOU } - }; - - unsigned int i = 0; - char *s; - - if (! sig || strlen (sig) == 0) - return (-1); - - if (sscanf (sig, "%u", &i) == 1) - { - if (i > 0 && i < sizeof (signallist) / sizeof (signallist[0])) - return (i); - eerrorx ("%s: `%s' is not a valid signal", progname, sig); - } - - if (strncmp (sig, "SIG", 3) == 0) - s = (char *) sig + 3; - else - s = NULL; - - for (i = 0; i < sizeof (signallist) / sizeof (signallist[0]); i++) - if (strcmp (sig, signallist[i].name) == 0 || - (s && strcmp (s, signallist[i].name) == 0)) - return (signallist[i].signal); - - eerrorx ("%s: `%s' is not a valid signal", progname, sig); + typedef struct signalpair + { + const char *name; + int signal; + } signalpair_t; + + static const signalpair_t signallist[] = { + { "ABRT", SIGABRT }, + { "ALRM", SIGALRM }, + { "FPE", SIGFPE }, + { "HUP", SIGHUP }, + { "ILL", SIGILL }, + { "INT", SIGINT }, + { "KILL", SIGKILL }, + { "PIPE", SIGPIPE }, + { "QUIT", SIGQUIT }, + { "SEGV", SIGSEGV }, + { "TERM", SIGTERM }, + { "USR1", SIGUSR1 }, + { "USR2", SIGUSR2 }, + { "CHLD", SIGCHLD }, + { "CONT", SIGCONT }, + { "STOP", SIGSTOP }, + { "TSTP", SIGTSTP }, + { "TTIN", SIGTTIN }, + { "TTOU", SIGTTOU } + }; + + unsigned int i = 0; + char *s; + + if (! sig || strlen (sig) == 0) + return (-1); + + if (sscanf (sig, "%u", &i) == 1) { + if (i > 0 && i < sizeof (signallist) / sizeof (signallist[0])) + return (i); + eerrorx ("%s: `%s' is not a valid signal", progname, sig); + } + + if (strncmp (sig, "SIG", 3) == 0) + s = (char *) sig + 3; + else + s = NULL; + + for (i = 0; i < sizeof (signallist) / sizeof (signallist[0]); i++) + if (strcmp (sig, signallist[i].name) == 0 || + (s && strcmp (s, signallist[i].name) == 0)) + return (signallist[i].signal); + + eerrorx ("%s: `%s' is not a valid signal", progname, sig); } static void parse_schedule_item (schedulelist_t *item, const char *string) { - const char *after_hyph; - int sig; - - if (strcmp (string,"forever") == 0) - item->type = schedule_forever; - else if (isdigit (string[0])) - { - item->type = schedule_timeout; - errno = 0; - if (sscanf (string, "%d", &item->value) != 1) - eerrorx ("%s: invalid timeout value in schedule `%s'", progname, - string); - } - else if ((after_hyph = string + (string[0] == '-')) && - ((sig = parse_signal (after_hyph)) != -1)) - { - item->type = schedule_signal; - item->value = (int) sig; - } - else - eerrorx ("%s: invalid schedule item `%s'", progname, string); + const char *after_hyph; + int sig; + + if (strcmp (string,"forever") == 0) + item->type = schedule_forever; + else if (isdigit (string[0])) { + item->type = schedule_timeout; + errno = 0; + if (sscanf (string, "%d", &item->value) != 1) + eerrorx ("%s: invalid timeout value in schedule `%s'", progname, + string); + } else if ((after_hyph = string + (string[0] == '-')) && + ((sig = parse_signal (after_hyph)) != -1)) + { + item->type = schedule_signal; + item->value = (int) sig; + } + else + eerrorx ("%s: invalid schedule item `%s'", progname, string); } static void parse_schedule (const char *string, int default_signal) { - char buffer[20]; - const char *slash; - int count = 0; - schedulelist_t *repeatat = NULL; - ptrdiff_t len; - schedulelist_t *next; - - if (string) - for (slash = string; *slash; slash++) - if (*slash == '/') - count++; - - if (schedule) - free_schedulelist (&schedule); - - schedule = rc_xmalloc (sizeof (schedulelist_t)); - schedule->gotolist = NULL; - - if (count == 0) - { - schedule->type = schedule_signal; - schedule->value = default_signal; - schedule->next = rc_xmalloc (sizeof (schedulelist_t)); - next = schedule->next; - next->type = schedule_timeout; - next->gotolist = NULL; - if (string) - { - if (sscanf (string, "%d", &next->value) != 1) - eerrorx ("%s: invalid timeout value in schedule", progname); - } - else - next->value = 5; - next->next = NULL; - - return; - } - - next = schedule; - while (string != NULL) - { - if ((slash = strchr (string, '/'))) - len = slash - string; - else - len = strlen (string); - - if (len >= (ptrdiff_t) sizeof (buffer)) - eerrorx ("%s: invalid schedule item, far too long", progname); - - memcpy (buffer, string, len); - buffer[len] = 0; - string = slash ? slash + 1 : NULL; - - parse_schedule_item (next, buffer); - if (next->type == schedule_forever) - { - if (repeatat) - eerrorx ("%s: invalid schedule, `forever' appears more than once", - progname); - - repeatat = next; - continue; - } - - if (string) - { - next->next = rc_xmalloc (sizeof (schedulelist_t)); - next = next->next; - next->gotolist = NULL; - } - } - - if (repeatat) - { - next->next = rc_xmalloc (sizeof (schedulelist_t)); - next = next->next; - next->type = schedule_goto; - next->value = 0; - next->gotolist = repeatat; - } - - next->next = NULL; - return; + char buffer[20]; + const char *slash; + int count = 0; + schedulelist_t *repeatat = NULL; + ptrdiff_t len; + schedulelist_t *next; + + if (string) + for (slash = string; *slash; slash++) + if (*slash == '/') + count++; + + if (schedule) + free_schedulelist (&schedule); + + schedule = rc_xmalloc (sizeof (schedulelist_t)); + schedule->gotolist = NULL; + + if (count == 0) { + schedule->type = schedule_signal; + schedule->value = default_signal; + schedule->next = rc_xmalloc (sizeof (schedulelist_t)); + next = schedule->next; + next->type = schedule_timeout; + next->gotolist = NULL; + if (string) { + if (sscanf (string, "%d", &next->value) != 1) + eerrorx ("%s: invalid timeout value in schedule", progname); + } + else + next->value = 5; + next->next = NULL; + + return; + } + + next = schedule; + while (string != NULL) { + if ((slash = strchr (string, '/'))) + len = slash - string; + else + len = strlen (string); + + if (len >= (ptrdiff_t) sizeof (buffer)) + eerrorx ("%s: invalid schedule item, far too long", progname); + + memcpy (buffer, string, len); + buffer[len] = 0; + string = slash ? slash + 1 : NULL; + + parse_schedule_item (next, buffer); + if (next->type == schedule_forever) { + if (repeatat) + eerrorx ("%s: invalid schedule, `forever' appears more than once", + progname); + + repeatat = next; + continue; + } + + if (string) { + next->next = rc_xmalloc (sizeof (schedulelist_t)); + next = next->next; + next->gotolist = NULL; + } + } + + if (repeatat) { + next->next = rc_xmalloc (sizeof (schedulelist_t)); + next = next->next; + next->type = schedule_goto; + next->value = 0; + next->gotolist = repeatat; + } + + next->next = NULL; + return; } static pid_t get_pid (const char *pidfile, bool quiet) { - FILE *fp; - pid_t pid; - - if (! pidfile) - return (-1); - - if ((fp = fopen (pidfile, "r")) == NULL) - { - if (! quiet) - eerror ("%s: fopen `%s': %s", progname, pidfile, strerror (errno)); - return (-1); - } - - if (fscanf (fp, "%d", &pid) != 1) - { - if (! quiet) - eerror ("%s: no pid found in `%s'", progname, pidfile); - fclose (fp); - return (-1); - } - fclose (fp); - - return (pid); + FILE *fp; + pid_t pid; + + if (! pidfile) + return (-1); + + if ((fp = fopen (pidfile, "r")) == NULL) { + if (! quiet) + eerror ("%s: fopen `%s': %s", progname, pidfile, strerror (errno)); + return (-1); + } + + if (fscanf (fp, "%d", &pid) != 1) { + if (! quiet) + eerror ("%s: no pid found in `%s'", progname, pidfile); + fclose (fp); + return (-1); + } + fclose (fp); + + return (pid); } /* return number of processed killed, -1 on error */ static int do_stop (const char *exec, const char *cmd, - const char *pidfile, uid_t uid,int sig, - bool quiet, bool verbose, bool test) + const char *pidfile, uid_t uid,int sig, + bool quiet, bool verbose, bool test) { - pid_t *pids; - bool killed; - int nkilled = 0; - pid_t pid = 0; - int i; - - if (pidfile) - if ((pid = get_pid (pidfile, quiet)) == -1) - return (quiet ? 0 : -1); - - if ((pids = rc_find_pids (exec, cmd, uid, pid)) == NULL) - return (0); - - for (i = 0; pids[i]; i++) - { - if (test) - { - if (! quiet) - einfo ("Would send signal %d to PID %d", sig, pids[i]); - nkilled++; - continue; - } - - if (verbose) - ebegin ("Sending signal %d to PID %d", sig, pids[i]); - errno = 0; - killed = (kill (pids[i], sig) == 0 || errno == ESRCH ? true : false); - if (! killed) - { - if (! quiet) - eerror ("%s: failed to send signal %d to PID %d: %s", - progname, sig, pids[i], strerror (errno)); - if (verbose) - eend (1, NULL); - nkilled = -1; - } - else - { - if (verbose) - eend (0, NULL); - if (nkilled != -1) - nkilled++; - } - } - - free (pids); - return (nkilled); + pid_t *pids; + bool killed; + int nkilled = 0; + pid_t pid = 0; + int i; + + if (pidfile) + if ((pid = get_pid (pidfile, quiet)) == -1) + return (quiet ? 0 : -1); + + if ((pids = rc_find_pids (exec, cmd, uid, pid)) == NULL) + return (0); + + for (i = 0; pids[i]; i++) { + if (test) { + if (! quiet) + einfo ("Would send signal %d to PID %d", sig, pids[i]); + nkilled++; + continue; + } + + if (verbose) + ebegin ("Sending signal %d to PID %d", sig, pids[i]); + errno = 0; + killed = (kill (pids[i], sig) == 0 || errno == ESRCH ? true : false); + if (! killed) { + if (! quiet) + eerror ("%s: failed to send signal %d to PID %d: %s", + progname, sig, pids[i], strerror (errno)); + if (verbose) + eend (1, NULL); + nkilled = -1; + } else { + if (verbose) + eend (0, NULL); + if (nkilled != -1) + nkilled++; + } + } + + free (pids); + return (nkilled); } static int run_stop_schedule (const char *exec, const char *cmd, - const char *pidfile, uid_t uid, - bool quiet, bool verbose, bool test) + const char *pidfile, uid_t uid, + bool quiet, bool verbose, bool test) { - schedulelist_t *item = schedule; - int nkilled = 0; - int tkilled = 0; - int nrunning = 0; - struct timeval tv; - struct timeval now; - struct timeval stopat; - - if (verbose) - { - if (pidfile) - einfo ("Will stop PID in pidfile `%s'", pidfile); - if (uid) - einfo ("Will stop processes owned by UID %d", uid); - if (exec) - einfo ("Will stop processes of `%s'", exec); - if (cmd) - einfo ("Will stop processes called `%s'", cmd); - } - - while (item) - { - switch (item->type) - { - case schedule_goto: - item = item->gotolist; - continue; - - case schedule_signal: - nrunning = 0; - nkilled = do_stop (exec, cmd, pidfile, uid, item->value, - quiet, verbose, test); - if (nkilled == 0) - { - if (tkilled == 0) - { - if (! quiet) - eerror ("%s: no matching processes found", progname); - } - return (tkilled); - } - else if (nkilled == -1) - return (0); - - tkilled += nkilled; - break; - case schedule_timeout: - if (item->value < 1) - { - item = NULL; - break; - } - - if (gettimeofday (&stopat, NULL) != 0) - { - eerror ("%s: gettimeofday: %s", progname, strerror (errno)); - return (0); - } - - stopat.tv_sec += item->value; - while (1) - { - if ((nrunning = do_stop (exec, cmd, pidfile, - uid, 0, true, false, true)) == 0) - return (true); - - tv.tv_sec = 0; - tv.tv_usec = POLL_INTERVAL; - if (select (0, 0, 0, 0, &tv) < 0) - { - if (errno == EINTR) - eerror ("%s: caught an interupt", progname); - else - eerror ("%s: select: %s", progname, strerror (errno)); - return (0); - } - - if (gettimeofday (&now, NULL) != 0) - { - eerror ("%s: gettimeofday: %s", progname, strerror (errno)); - return (0); - } - if (timercmp (&now, &stopat, >)) - break; - } - break; - - default: - eerror ("%s: invalid schedule item `%d'", progname, item->type); - return (0); - } - - if (item) - item = item->next; - } - - if (test || (tkilled > 0 && nrunning == 0)) - return (nkilled); - - if (! quiet) - { - if (nrunning == 1) - eerror ("%s: %d process refused to stop", progname, nrunning); - else - eerror ("%s: %d process(es) refused to stop", progname, nrunning); - } - - return (-nrunning); + schedulelist_t *item = schedule; + int nkilled = 0; + int tkilled = 0; + int nrunning = 0; + struct timeval tv; + struct timeval now; + struct timeval stopat; + + if (verbose) { + if (pidfile) + einfo ("Will stop PID in pidfile `%s'", pidfile); + if (uid) + einfo ("Will stop processes owned by UID %d", uid); + if (exec) + einfo ("Will stop processes of `%s'", exec); + if (cmd) + einfo ("Will stop processes called `%s'", cmd); + } + + while (item) { + switch (item->type) { + case schedule_goto: + item = item->gotolist; + continue; + + case schedule_signal: + nrunning = 0; + nkilled = do_stop (exec, cmd, pidfile, uid, item->value, + quiet, verbose, test); + if (nkilled == 0) { + if (tkilled == 0) { + if (! quiet) + eerror ("%s: no matching processes found", progname); + } + return (tkilled); + } + else if (nkilled == -1) + return (0); + + tkilled += nkilled; + break; + case schedule_timeout: + if (item->value < 1) { + item = NULL; + break; + } + + if (gettimeofday (&stopat, NULL) != 0) { + eerror ("%s: gettimeofday: %s", progname, strerror (errno)); + return (0); + } + + stopat.tv_sec += item->value; + while (1) { + if ((nrunning = do_stop (exec, cmd, pidfile, + uid, 0, true, false, true)) == 0) + return (true); + + tv.tv_sec = 0; + tv.tv_usec = POLL_INTERVAL; + if (select (0, 0, 0, 0, &tv) < 0) { + if (errno == EINTR) + eerror ("%s: caught an interupt", progname); + else + eerror ("%s: select: %s", progname, strerror (errno)); + return (0); + } + + if (gettimeofday (&now, NULL) != 0) { + eerror ("%s: gettimeofday: %s", progname, strerror (errno)); + return (0); + } + if (timercmp (&now, &stopat, >)) + break; + } + break; + + default: + eerror ("%s: invalid schedule item `%d'", progname, item->type); + return (0); + } + + if (item) + item = item->next; + } + + if (test || (tkilled > 0 && nrunning == 0)) + return (nkilled); + + if (! quiet) { + if (nrunning == 1) + eerror ("%s: %d process refused to stop", progname, nrunning); + else + eerror ("%s: %d process(es) refused to stop", progname, nrunning); + } + + return (-nrunning); } static void handle_signal (int sig) { - int pid; - int status; - int serrno = errno; - char signame[10] = { '\0' }; - - switch (sig) - { - case SIGINT: - if (! signame[0]) - snprintf (signame, sizeof (signame), "SIGINT"); - case SIGTERM: - if (! signame[0]) - snprintf (signame, sizeof (signame), "SIGTERM"); - case SIGQUIT: - if (! signame[0]) - snprintf (signame, sizeof (signame), "SIGQUIT"); - eerrorx ("%s: caught %s, aborting", progname, signame); - - case SIGCHLD: - while (1) - { - if ((pid = waitpid (-1, &status, WNOHANG)) < 0) - { - if (errno != ECHILD) - eerror ("%s: waitpid: %s", progname, strerror (errno)); - break; - } - } - break; - - default: - eerror ("%s: caught unknown signal %d", progname, sig); - } - - /* Restore errno */ - errno = serrno; + int pid; + int status; + int serrno = errno; + char signame[10] = { '\0' }; + + switch (sig) { + case SIGINT: + if (! signame[0]) + snprintf (signame, sizeof (signame), "SIGINT"); + case SIGTERM: + if (! signame[0]) + snprintf (signame, sizeof (signame), "SIGTERM"); + case SIGQUIT: + if (! signame[0]) + snprintf (signame, sizeof (signame), "SIGQUIT"); + eerrorx ("%s: caught %s, aborting", progname, signame); + + case SIGCHLD: + while (1) { + if ((pid = waitpid (-1, &status, WNOHANG)) < 0) { + if (errno != ECHILD) + eerror ("%s: waitpid: %s", progname, strerror (errno)); + break; + } + } + break; + + default: + eerror ("%s: caught unknown signal %d", progname, sig); + } + + /* Restore errno */ + errno = serrno; } int main (int argc, char **argv) { - int devnull_fd = -1; + int devnull_fd = -1; #ifdef TIOCNOTTY - int tty_fd = -1; + int tty_fd = -1; #endif #ifdef HAVE_PAM - pam_handle_t *pamh = NULL; - int pamr; + pam_handle_t *pamh = NULL; + int pamr; #endif - static struct option longopts[] = { - { "stop", 0, NULL, 'K'}, - { "nicelevel", 1, NULL, 'N'}, - { "retry", 1, NULL, 'R'}, - { "start", 0, NULL, 'S'}, - { "background", 0, NULL, 'b'}, - { "chuid", 1, NULL, 'c'}, - { "chdir", 1, NULL, 'd'}, - { "group", 1, NULL, 'g'}, - { "make-pidfile", 0, NULL, 'm'}, - { "name", 1, NULL, 'n'}, - { "oknodo", 0, NULL, 'o'}, - { "pidfile", 1, NULL, 'p'}, - { "quiet", 0, NULL, 'q'}, - { "signal", 1, NULL, 's'}, - { "test", 0, NULL, 't'}, - { "user", 1, NULL, 'u'}, - { "chroot", 1, NULL, 'r'}, - { "verbose", 0, NULL, 'v'}, - { "exec", 1, NULL, 'x'}, - { "stdout", 1, NULL, '1'}, - { "stderr", 1, NULL, '2'}, - { NULL, 0, NULL, 0} - }; - int c; - bool start = false; - bool stop = false; - bool oknodo = false; - bool test = false; - bool quiet = false; - bool verbose = false; - char *exec = NULL; - char *cmd = NULL; - char *pidfile = NULL; - int sig = SIGTERM; - uid_t uid = 0; - int nicelevel = 0; - bool background = false; - bool makepidfile = false; - uid_t ch_uid = 0; - gid_t ch_gid = 0; - char *ch_root = NULL; - char *ch_dir = NULL; - int tid = 0; - char *redirect_stderr = NULL; - char *redirect_stdout = NULL; - int stdout_fd; - int stderr_fd; - pid_t pid; - struct timeval tv; - int i; - char *svcname = getenv ("SVCNAME"); - char *env; - - progname = argv[0]; - atexit (cleanup); - - signal (SIGINT, handle_signal); - signal (SIGQUIT, handle_signal); - signal (SIGTERM, handle_signal); - - while ((c = getopt_long (argc, argv, - "KN:R:Sbc:d:g:mn:op:qs:tu:r:vx:1:2:", - longopts, (int *) 0)) != -1) - switch (c) - { - case 'K': /* --stop */ - stop = true; - break; - - case 'N': /* --nice */ - if (sscanf (optarg, "%d", &nicelevel) != 1) - eerrorx ("%s: invalid nice level `%s'", progname, optarg); - break; - - case 'R': /* --retry <schedule>|<timeout> */ - parse_schedule (optarg, sig); - break; - - case 'S': /* --start */ - start = true; - break; - - case 'b': /* --background */ - background = true; - break; - - case 'c': /* --chuid <username>|<uid> */ - /* we copy the string just in case we need the - * argument later. */ - { - char *p = optarg; - char *cu = strsep (&p, ":"); - changeuser = strdup (cu); - if (sscanf (cu, "%d", &tid) != 1) - { - struct passwd *pw = getpwnam (cu); - if (! pw) - eerrorx ("%s: user `%s' not found", progname, cu); - ch_uid = pw->pw_uid; - } - else - ch_uid = tid; - if (p) - { - char *cg = strsep (&p, ":"); - if (sscanf (cg, "%d", &tid) != 1) - { - struct group *gr = getgrnam (cg); - if (! gr) - eerrorx ("%s: group `%s' not found", progname, cg); - ch_gid = gr->gr_gid; - } - else - ch_gid = tid; - } - } - break; - - case 'd': /* --chdir /new/dir */ - ch_dir = optarg; - break; - - case 'g': /* --group <group>|<gid> */ - if (sscanf (optarg, "%d", &tid) != 1) - { - struct group *gr = getgrnam (optarg); - if (! gr) - eerrorx ("%s: group `%s' not found", progname, optarg); - ch_gid = gr->gr_gid; - } - else - ch_gid = tid; - break; - - case 'm': /* --make-pidfile */ - makepidfile = true; - break; - - case 'n': /* --name <process-name> */ - cmd = optarg; - break; - - case 'o': /* --oknodo */ - oknodo = true; - break; - - case 'p': /* --pidfile <pid-file> */ - pidfile = optarg; - break; - - case 'q': /* --quiet */ - quiet = true; - break; - - case 's': /* --signal <signal> */ - sig = parse_signal (optarg); - break; - - case 't': /* --test */ - test = true; - break; - - case 'u': /* --user <username>|<uid> */ - if (sscanf (optarg, "%d", &tid) != 1) - { - struct passwd *pw = getpwnam (optarg); - if (! pw) - eerrorx ("%s: user `%s' not found", progname, optarg); - uid = pw->pw_uid; - } - else - uid = tid; - break; - - case 'r': /* --chroot /new/root */ - ch_root = optarg; - break; - - case 'v': /* --verbose */ - verbose = true; - break; - - case 'x': /* --exec <executable> */ - exec = optarg; - break; - - case '1': /* --stdout /path/to/stdout.lgfile */ - redirect_stdout = optarg; - break; - - case '2': /* --stderr /path/to/stderr.logfile */ - redirect_stderr = optarg; - break; - - default: - exit (EXIT_FAILURE); - } - - /* Respect RC as well as how we are called */ - if (rc_is_env ("RC_QUIET", "yes") && ! verbose) - quiet = true; - - if (start == stop) - eerrorx ("%s: need one of --start or --stop", progname); - - if (start && ! exec) - eerrorx ("%s: --start needs --exec", progname); - - if (stop && ! exec && ! pidfile && ! cmd && ! uid) - eerrorx ("%s: --stop needs --exec, --pidfile, --name or --user", progname); - - if (makepidfile && ! pidfile) - eerrorx ("%s: --make-pidfile is only relevant with --pidfile", progname); - - if (background && ! start) - eerrorx ("%s: --background is only relevant with --start", progname); - - if ((redirect_stdout || redirect_stderr) && ! background) - eerrorx ("%s: --stdout and --stderr are only relevant with --background", - progname); - - argc -= optind; - argv += optind; - - /* Validate that the binary rc_exists if we are starting */ - if (exec && start) - { - char *tmp; - if (ch_root) - tmp = rc_strcatpaths (ch_root, exec, (char *) NULL); - else - tmp = exec; - if (! rc_is_file (tmp)) - { - eerror ("%s: %s does not exist", progname, tmp); - if (ch_root) - free (tmp); - exit (EXIT_FAILURE); - } - if (ch_root) - free (tmp); - } - - if (stop) - { - int result; - - if (! schedule) - { - if (test || oknodo) - parse_schedule ("0", sig); - else - parse_schedule (NULL, sig); - } - - result = run_stop_schedule (exec, cmd, pidfile, uid, quiet, verbose, test); - if (test || oknodo) - return (result > 0 ? EXIT_SUCCESS : EXIT_FAILURE); - if (result < 1) - exit (result == 0 ? EXIT_SUCCESS : EXIT_FAILURE); - - if (pidfile && rc_is_file (pidfile)) - unlink (pidfile); - - if (svcname) - rc_set_service_daemon (svcname, exec, cmd, pidfile, false); - - exit (EXIT_SUCCESS); - } - - if (do_stop (exec, cmd, pidfile, uid, 0, true, false, true) > 0) - eerrorx ("%s: %s is already running", progname, exec); - - if (test) - { - if (quiet) - exit (EXIT_SUCCESS); - - einfon ("Would start %s", exec); - while (argc-- > 0) - printf("%s ", *argv++); - printf ("\n"); - eindent (); - if (ch_uid != 0) - einfo ("as user %d", ch_uid); - if (ch_gid != 0) - einfo ("as group %d", ch_gid); - if (ch_root) - einfo ("in root `%s'", ch_root); - if (ch_dir) - einfo ("in dir `%s'", ch_dir); - if (nicelevel != 0) - einfo ("with a priority of %d", nicelevel); - eoutdent (); - exit (EXIT_SUCCESS); - } - - /* Ensure this is unset, so if the daemon does /etc/init.d/foo - Then we filter the environment accordingly */ - unsetenv ("RC_SOFTLEVEL"); - - if (verbose) - { - ebegin ("Detaching to start `%s'", exec); - eindent (); - } - - if (background) - signal (SIGCHLD, handle_signal); - - *--argv = exec; - if ((pid = fork ()) == -1) - eerrorx ("%s: fork: %s", progname, strerror (errno)); - - /* Child process - lets go! */ - if (pid == 0) - { - pid_t mypid = getpid (); + static struct option longopts[] = { + { "stop", 0, NULL, 'K'}, + { "nicelevel", 1, NULL, 'N'}, + { "retry", 1, NULL, 'R'}, + { "start", 0, NULL, 'S'}, + { "background", 0, NULL, 'b'}, + { "chuid", 1, NULL, 'c'}, + { "chdir", 1, NULL, 'd'}, + { "group", 1, NULL, 'g'}, + { "make-pidfile", 0, NULL, 'm'}, + { "name", 1, NULL, 'n'}, + { "oknodo", 0, NULL, 'o'}, + { "pidfile", 1, NULL, 'p'}, + { "quiet", 0, NULL, 'q'}, + { "signal", 1, NULL, 's'}, + { "test", 0, NULL, 't'}, + { "user", 1, NULL, 'u'}, + { "chroot", 1, NULL, 'r'}, + { "verbose", 0, NULL, 'v'}, + { "exec", 1, NULL, 'x'}, + { "stdout", 1, NULL, '1'}, + { "stderr", 1, NULL, '2'}, + { NULL, 0, NULL, 0} + }; + int c; + bool start = false; + bool stop = false; + bool oknodo = false; + bool test = false; + bool quiet = false; + bool verbose = false; + char *exec = NULL; + char *cmd = NULL; + char *pidfile = NULL; + int sig = SIGTERM; + uid_t uid = 0; + int nicelevel = 0; + bool background = false; + bool makepidfile = false; + uid_t ch_uid = 0; + gid_t ch_gid = 0; + char *ch_root = NULL; + char *ch_dir = NULL; + int tid = 0; + char *redirect_stderr = NULL; + char *redirect_stdout = NULL; + int stdout_fd; + int stderr_fd; + pid_t pid; + struct timeval tv; + int i; + char *svcname = getenv ("SVCNAME"); + char *env; + + progname = argv[0]; + atexit (cleanup); + + signal (SIGINT, handle_signal); + signal (SIGQUIT, handle_signal); + signal (SIGTERM, handle_signal); + + while ((c = getopt_long (argc, argv, + "KN:R:Sbc:d:g:mn:op:qs:tu:r:vx:1:2:", + longopts, (int *) 0)) != -1) + switch (c) { + case 'K': /* --stop */ + stop = true; + break; + + case 'N': /* --nice */ + if (sscanf (optarg, "%d", &nicelevel) != 1) + eerrorx ("%s: invalid nice level `%s'", progname, optarg); + break; + + case 'R': /* --retry <schedule>|<timeout> */ + parse_schedule (optarg, sig); + break; + + case 'S': /* --start */ + start = true; + break; + + case 'b': /* --background */ + background = true; + break; + + case 'c': /* --chuid <username>|<uid> */ + /* we copy the string just in case we need the + * argument later. */ + { + char *p = optarg; + char *cu = strsep (&p, ":"); + changeuser = strdup (cu); + if (sscanf (cu, "%d", &tid) != 1) { + struct passwd *pw = getpwnam (cu); + if (! pw) + eerrorx ("%s: user `%s' not found", progname, cu); + ch_uid = pw->pw_uid; + } else + ch_uid = tid; + if (p) { + char *cg = strsep (&p, ":"); + if (sscanf (cg, "%d", &tid) != 1) { + struct group *gr = getgrnam (cg); + if (! gr) + eerrorx ("%s: group `%s' not found", progname, cg); + ch_gid = gr->gr_gid; + } else + ch_gid = tid; + } + } + break; + + case 'd': /* --chdir /new/dir */ + ch_dir = optarg; + break; + + case 'g': /* --group <group>|<gid> */ + if (sscanf (optarg, "%d", &tid) != 1) { + struct group *gr = getgrnam (optarg); + if (! gr) + eerrorx ("%s: group `%s' not found", progname, optarg); + ch_gid = gr->gr_gid; + } else + ch_gid = tid; + break; + + case 'm': /* --make-pidfile */ + makepidfile = true; + break; + + case 'n': /* --name <process-name> */ + cmd = optarg; + break; + + case 'o': /* --oknodo */ + oknodo = true; + break; + + case 'p': /* --pidfile <pid-file> */ + pidfile = optarg; + break; + + case 'q': /* --quiet */ + quiet = true; + break; + + case 's': /* --signal <signal> */ + sig = parse_signal (optarg); + break; + + case 't': /* --test */ + test = true; + break; + + case 'u': /* --user <username>|<uid> */ + if (sscanf (optarg, "%d", &tid) != 1) { + struct passwd *pw = getpwnam (optarg); + if (! pw) + eerrorx ("%s: user `%s' not found", progname, optarg); + uid = pw->pw_uid; + } else + uid = tid; + break; + + case 'r': /* --chroot /new/root */ + ch_root = optarg; + break; + + case 'v': /* --verbose */ + verbose = true; + break; + + case 'x': /* --exec <executable> */ + exec = optarg; + break; + + case '1': /* --stdout /path/to/stdout.lgfile */ + redirect_stdout = optarg; + break; + + case '2': /* --stderr /path/to/stderr.logfile */ + redirect_stderr = optarg; + break; + + default: + exit (EXIT_FAILURE); + } + + /* Respect RC as well as how we are called */ + if (rc_is_env ("RC_QUIET", "yes") && ! verbose) + quiet = true; + + if (start == stop) + eerrorx ("%s: need one of --start or --stop", progname); + + if (start && ! exec) + eerrorx ("%s: --start needs --exec", progname); + + if (stop && ! exec && ! pidfile && ! cmd && ! uid) + eerrorx ("%s: --stop needs --exec, --pidfile, --name or --user", progname); + + if (makepidfile && ! pidfile) + eerrorx ("%s: --make-pidfile is only relevant with --pidfile", progname); + + if (background && ! start) + eerrorx ("%s: --background is only relevant with --start", progname); + + if ((redirect_stdout || redirect_stderr) && ! background) + eerrorx ("%s: --stdout and --stderr are only relevant with --background", + progname); + + argc -= optind; + argv += optind; + + /* Validate that the binary rc_exists if we are starting */ + if (exec && start) { + char *tmp; + if (ch_root) + tmp = rc_strcatpaths (ch_root, exec, (char *) NULL); + else + tmp = exec; + if (! rc_is_file (tmp)) { + eerror ("%s: %s does not exist", progname, tmp); + if (ch_root) + free (tmp); + exit (EXIT_FAILURE); + } + if (ch_root) + free (tmp); + } + + if (stop) { + int result; + + if (! schedule) { + if (test || oknodo) + parse_schedule ("0", sig); + else + parse_schedule (NULL, sig); + } + + result = run_stop_schedule (exec, cmd, pidfile, uid, quiet, verbose, test); + if (test || oknodo) + return (result > 0 ? EXIT_SUCCESS : EXIT_FAILURE); + if (result < 1) + exit (result == 0 ? EXIT_SUCCESS : EXIT_FAILURE); + + if (pidfile && rc_is_file (pidfile)) + unlink (pidfile); + + if (svcname) + rc_set_service_daemon (svcname, exec, cmd, pidfile, false); + + exit (EXIT_SUCCESS); + } + + if (do_stop (exec, cmd, pidfile, uid, 0, true, false, true) > 0) + eerrorx ("%s: %s is already running", progname, exec); + + if (test) { + if (quiet) + exit (EXIT_SUCCESS); + + einfon ("Would start %s", exec); + while (argc-- > 0) + printf("%s ", *argv++); + printf ("\n"); + eindent (); + if (ch_uid != 0) + einfo ("as user %d", ch_uid); + if (ch_gid != 0) + einfo ("as group %d", ch_gid); + if (ch_root) + einfo ("in root `%s'", ch_root); + if (ch_dir) + einfo ("in dir `%s'", ch_dir); + if (nicelevel != 0) + einfo ("with a priority of %d", nicelevel); + eoutdent (); + exit (EXIT_SUCCESS); + } + + /* Ensure this is unset, so if the daemon does /etc/init.d/foo + Then we filter the environment accordingly */ + unsetenv ("RC_SOFTLEVEL"); + + if (verbose) { + ebegin ("Detaching to start `%s'", exec); + eindent (); + } + + if (background) + signal (SIGCHLD, handle_signal); + + *--argv = exec; + if ((pid = fork ()) == -1) + eerrorx ("%s: fork: %s", progname, strerror (errno)); + + /* Child process - lets go! */ + if (pid == 0) { + pid_t mypid = getpid (); #ifdef TIOCNOTTY - tty_fd = open("/dev/tty", O_RDWR); + tty_fd = open("/dev/tty", O_RDWR); #endif - devnull_fd = open("/dev/null", O_RDWR); + devnull_fd = open("/dev/null", O_RDWR); - if (nicelevel) - { - if (setpriority (PRIO_PROCESS, mypid, nicelevel) == -1) - eerrorx ("%s: setpritory %d: %s", progname, nicelevel, - strerror(errno)); - } + if (nicelevel) { + if (setpriority (PRIO_PROCESS, mypid, nicelevel) == -1) + eerrorx ("%s: setpritory %d: %s", progname, nicelevel, + strerror(errno)); + } - if (ch_root && chroot (ch_root) < 0) - eerrorx ("%s: chroot `%s': %s", progname, ch_root, strerror (errno)); + if (ch_root && chroot (ch_root) < 0) + eerrorx ("%s: chroot `%s': %s", progname, ch_root, strerror (errno)); - if (ch_dir && chdir (ch_dir) < 0) - eerrorx ("%s: chdir `%s': %s", progname, ch_dir, strerror (errno)); + if (ch_dir && chdir (ch_dir) < 0) + eerrorx ("%s: chdir `%s': %s", progname, ch_dir, strerror (errno)); - if (makepidfile && pidfile) - { - FILE *fp = fopen (pidfile, "w"); - if (! fp) - eerrorx ("%s: fopen `%s': %s", progname, pidfile, strerror - (errno)); - fprintf (fp, "%d\n", mypid); - fclose (fp); - } + if (makepidfile && pidfile) { + FILE *fp = fopen (pidfile, "w"); + if (! fp) + eerrorx ("%s: fopen `%s': %s", progname, pidfile, strerror + (errno)); + fprintf (fp, "%d\n", mypid); + fclose (fp); + } #ifdef HAVE_PAM - if (changeuser != NULL) - pamr = pam_start ("start-stop-daemon", changeuser, &conv, &pamh); - else - pamr = pam_start ("start-stop-daemon", "nobody", &conv, &pamh); - - if (pamr == PAM_SUCCESS) - pamr = pam_authenticate (pamh, PAM_SILENT); - if (pamr == PAM_SUCCESS) - pamr = pam_acct_mgmt (pamh, PAM_SILENT); - if (pamr == PAM_SUCCESS) - pamr = pam_open_session (pamh, PAM_SILENT); - if (pamr != PAM_SUCCESS) - eerrorx ("%s: pam error: %s", progname, pam_strerror(pamh, pamr)); + if (changeuser != NULL) + pamr = pam_start ("start-stop-daemon", changeuser, &conv, &pamh); + else + pamr = pam_start ("start-stop-daemon", "nobody", &conv, &pamh); + + if (pamr == PAM_SUCCESS) + pamr = pam_authenticate (pamh, PAM_SILENT); + if (pamr == PAM_SUCCESS) + pamr = pam_acct_mgmt (pamh, PAM_SILENT); + if (pamr == PAM_SUCCESS) + pamr = pam_open_session (pamh, PAM_SILENT); + if (pamr != PAM_SUCCESS) + eerrorx ("%s: pam error: %s", progname, pam_strerror(pamh, pamr)); #endif - if ((ch_gid) && setgid(ch_gid)) - eerrorx ("%s: unable to set groupid to %d", progname, ch_gid); - if (changeuser && ch_gid) - if (initgroups (changeuser, ch_gid)) - eerrorx ("%s: initgroups (%s, %d)", progname, changeuser, ch_gid); - if (ch_uid && setuid (ch_uid)) - eerrorx ("%s: unable to set userid to %d", progname, ch_uid); - else - { - struct passwd *passwd = getpwuid (ch_uid); - if (passwd) - { - unsetenv ("HOME"); - if (passwd->pw_dir) - setenv ("HOME", passwd->pw_dir, 1); - unsetenv ("USER"); - if (passwd->pw_name) - setenv ("USER", passwd->pw_name, 1); - } - } - - /* Close any fd's to the passwd database */ - endpwent (); + if ((ch_gid) && setgid(ch_gid)) + eerrorx ("%s: unable to set groupid to %d", progname, ch_gid); + if (changeuser && ch_gid) + if (initgroups (changeuser, ch_gid)) + eerrorx ("%s: initgroups (%s, %d)", progname, changeuser, ch_gid); + if (ch_uid && setuid (ch_uid)) + eerrorx ("%s: unable to set userid to %d", progname, ch_uid); + else { + struct passwd *passwd = getpwuid (ch_uid); + if (passwd) { + unsetenv ("HOME"); + if (passwd->pw_dir) + setenv ("HOME", passwd->pw_dir, 1); + unsetenv ("USER"); + if (passwd->pw_name) + setenv ("USER", passwd->pw_name, 1); + } + } + + /* Close any fd's to the passwd database */ + endpwent (); #ifdef TIOCNOTTY - ioctl(tty_fd, TIOCNOTTY, 0); - close(tty_fd); + ioctl(tty_fd, TIOCNOTTY, 0); + close(tty_fd); #endif - /* Clean the environment of any RC_ variables */ - STRLIST_FOREACH (environ, env, i) - if (env && strncmp (env, "RC_", 3) != 0) - { - /* For the path character, remove the rcscript bin dir from it */ - if (strncmp (env, "PATH=" RC_LIBDIR "bin:", - strlen ("PATH=" RC_LIBDIR "bin:")) == 0) - { - char *path = env; - char *newpath; - int len; - path += strlen ("PATH=" RC_LIBDIR "bin:"); - len = sizeof (char *) * strlen (path) + 6; - newpath = rc_xmalloc (len); - snprintf (newpath, len, "PATH=%s", path); - newenv = rc_strlist_add (newenv, newpath); - free (newpath); - } - else - newenv = rc_strlist_add (newenv, env); - } - - umask (022); - - stdout_fd = devnull_fd; - stderr_fd = devnull_fd; - if (redirect_stdout) - { - if ((stdout_fd = open (redirect_stdout, O_WRONLY | O_CREAT | O_APPEND, - S_IRUSR | S_IWUSR)) == -1) - eerrorx ("%s: unable to open the logfile for stdout `%s': %s", - progname, redirect_stdout, strerror (errno)); - } - if (redirect_stderr) - { - if ((stderr_fd = open (redirect_stderr, O_WRONLY | O_CREAT | O_APPEND, - S_IRUSR | S_IWUSR)) == -1) - eerrorx ("%s: unable to open the logfile for stderr `%s': %s", - progname, redirect_stderr, strerror (errno)); - } - - dup2 (devnull_fd, STDIN_FILENO); - if (background) - { - dup2 (stdout_fd, STDOUT_FILENO); - dup2 (stderr_fd, STDERR_FILENO); - } - - for (i = getdtablesize () - 1; i >= 3; --i) - close(i); - - setsid (); - - execve (exec, argv, newenv); + /* Clean the environment of any RC_ variables */ + STRLIST_FOREACH (environ, env, i) + if (env && strncmp (env, "RC_", 3) != 0) { + /* For the path character, remove the rcscript bin dir from it */ + if (strncmp (env, "PATH=" RC_LIBDIR "bin:", + strlen ("PATH=" RC_LIBDIR "bin:")) == 0) + { + char *path = env; + char *newpath; + int len; + path += strlen ("PATH=" RC_LIBDIR "bin:"); + len = sizeof (char *) * strlen (path) + 6; + newpath = rc_xmalloc (len); + snprintf (newpath, len, "PATH=%s", path); + newenv = rc_strlist_add (newenv, newpath); + free (newpath); + } else + newenv = rc_strlist_add (newenv, env); + } + + umask (022); + + stdout_fd = devnull_fd; + stderr_fd = devnull_fd; + if (redirect_stdout) { + if ((stdout_fd = open (redirect_stdout, O_WRONLY | O_CREAT | O_APPEND, + S_IRUSR | S_IWUSR)) == -1) + eerrorx ("%s: unable to open the logfile for stdout `%s': %s", + progname, redirect_stdout, strerror (errno)); + } + if (redirect_stderr) { + if ((stderr_fd = open (redirect_stderr, O_WRONLY | O_CREAT | O_APPEND, + S_IRUSR | S_IWUSR)) == -1) + eerrorx ("%s: unable to open the logfile for stderr `%s': %s", + progname, redirect_stderr, strerror (errno)); + } + + if (background) { + /* Hmmm, some daemons may need stdin? */ + dup2 (devnull_fd, STDIN_FILENO); + dup2 (stdout_fd, STDOUT_FILENO); + dup2 (stderr_fd, STDERR_FILENO); + } + + for (i = getdtablesize () - 1; i >= 3; --i) + close(i); + + setsid (); + + execve (exec, argv, newenv); #ifdef HAVE_PAM - if (pamr == PAM_SUCCESS) - pam_close_session (pamh, PAM_SILENT); + if (pamr == PAM_SUCCESS) + pam_close_session (pamh, PAM_SILENT); #endif - eerrorx ("%s: failed to exec `%s': %s", progname, exec, strerror (errno)); - } - - /* Parent process */ - if (! background) - { - /* As we're not backgrounding the process, wait for our pid to return */ - int status = 0; - int savepid = pid; - - errno = 0; - do - { - pid = waitpid (savepid, &status, 0); - if (pid < 1) - { - eerror ("waitpid %d: %s", savepid, strerror (errno)); - return (-1); - } - } while (! WIFEXITED (status) && ! WIFSIGNALED (status)); - - if (! WIFEXITED (status) || WEXITSTATUS (status) != 0) - { - if (! quiet) - eerrorx ("%s: failed to started `%s'", progname, exec); - exit (EXIT_FAILURE); - } - - pid = savepid; - } - - /* Wait a little bit and check that process is still running - We do this as some badly written daemons fork and then barf */ - if (START_WAIT > 0) - { - struct timeval stopat; - struct timeval now; - - if (gettimeofday (&stopat, NULL) != 0) - eerrorx ("%s: gettimeofday: %s", progname, strerror (errno)); - - stopat.tv_usec += START_WAIT; - while (1) - { - bool alive = false; - - tv.tv_sec = 0; - tv.tv_usec = POLL_INTERVAL; - if (select (0, 0, 0, 0, &tv) < 0) - { - /* Let our signal handler handle the interupt */ - if (errno != EINTR) - eerrorx ("%s: select: %s", progname, strerror (errno)); - } - - if (gettimeofday (&now, NULL) != 0) - eerrorx ("%s: gettimeofday: %s", progname, strerror (errno)); - - /* This is knarly. - If we backgrounded then we know the exact pid. - Otherwise if we have a pidfile then it *may* know the exact pid. - Failing that, we'll have to query processes. - We sleep first as some programs like ntp like to fork, and write - their pidfile a LONG time later. */ - if (background) - { - if (kill (pid, 0) == 0) - alive = true; - } - else - { - if (pidfile && rc_exists (pidfile)) - { - if (do_stop (NULL, NULL, pidfile, uid, 0, true, false, true) > 0) - alive = true; - } - else - { - if (do_stop (exec, cmd, NULL, uid, 0, true, false, true) > 0) - alive = true; - } - } - - if (! alive) - eerrorx ("%s: %s died", progname, exec); - - if (timercmp (&now, &stopat, >)) - break; - } - } - - if (svcname) - rc_set_service_daemon (svcname, exec, cmd, pidfile, true); - - exit (EXIT_SUCCESS); + eerrorx ("%s: failed to exec `%s': %s", progname, exec, strerror (errno)); + } + + /* Parent process */ + if (! background) { + /* As we're not backgrounding the process, wait for our pid to return */ + int status = 0; + int savepid = pid; + + errno = 0; + do { + pid = waitpid (savepid, &status, 0); + if (pid < 1) { + eerror ("waitpid %d: %s", savepid, strerror (errno)); + return (-1); + } + } while (! WIFEXITED (status) && ! WIFSIGNALED (status)); + + if (! WIFEXITED (status) || WEXITSTATUS (status) != 0) { + if (! quiet) + eerrorx ("%s: failed to started `%s'", progname, exec); + exit (EXIT_FAILURE); + } + + pid = savepid; + } + + /* Wait a little bit and check that process is still running + We do this as some badly written daemons fork and then barf */ + if (START_WAIT > 0) { + struct timeval stopat; + struct timeval now; + + if (gettimeofday (&stopat, NULL) != 0) + eerrorx ("%s: gettimeofday: %s", progname, strerror (errno)); + + stopat.tv_usec += START_WAIT; + while (1) { + bool alive = false; + + tv.tv_sec = 0; + tv.tv_usec = POLL_INTERVAL; + if (select (0, 0, 0, 0, &tv) < 0) { + /* Let our signal handler handle the interupt */ + if (errno != EINTR) + eerrorx ("%s: select: %s", progname, strerror (errno)); + } + + if (gettimeofday (&now, NULL) != 0) + eerrorx ("%s: gettimeofday: %s", progname, strerror (errno)); + + /* This is knarly. + If we backgrounded then we know the exact pid. + Otherwise if we have a pidfile then it *may* know the exact pid. + Failing that, we'll have to query processes. + We sleep first as some programs like ntp like to fork, and write + their pidfile a LONG time later. */ + if (background) { + if (kill (pid, 0) == 0) + alive = true; + } else { + if (pidfile && rc_exists (pidfile)) { + if (do_stop (NULL, NULL, pidfile, uid, 0, true, false, true) > 0) + alive = true; + } else { + if (do_stop (exec, cmd, NULL, uid, 0, true, false, true) > 0) + alive = true; + } + } + + if (! alive) + eerrorx ("%s: %s died", progname, exec); + + if (timercmp (&now, &stopat, >)) + break; + } + } + + if (svcname) + rc_set_service_daemon (svcname, exec, cmd, pidfile, true); + + exit (EXIT_SUCCESS); } |