diff options
Diffstat (limited to 'src/rc/start-stop-daemon.c')
-rw-r--r-- | src/rc/start-stop-daemon.c | 402 |
1 files changed, 8 insertions, 394 deletions
diff --git a/src/rc/start-stop-daemon.c b/src/rc/start-stop-daemon.c index 451d4a5c..df5b3184 100644 --- a/src/rc/start-stop-daemon.c +++ b/src/rc/start-stop-daemon.c @@ -19,10 +19,6 @@ * except according to the terms contained in the LICENSE file. */ -/* nano seconds */ -#define POLL_INTERVAL 20000000 -#define WAIT_PIDFILE 500000000 -#define ONE_SECOND 1000000000 #define ONE_MS 1000000 #include <sys/types.h> @@ -63,6 +59,7 @@ static struct pam_conv conv = { NULL, NULL}; #include "queue.h" #include "rc.h" #include "rc-misc.h" +#include "rc-schedules.h" #include "_usage.h" #include "helpers.h" @@ -130,20 +127,6 @@ const char * const longopts_help[] = { }; const char *usagestring = NULL; -typedef struct scheduleitem -{ - enum - { - SC_TIMEOUT, - SC_SIGNAL, - SC_GOTO, - SC_FOREVER - } type; - int value; - struct scheduleitem *gotoitem; - TAILQ_ENTRY(scheduleitem) entries; -} SCHEDULEITEM; -TAILQ_HEAD(, scheduleitem) schedule; static char **nav; static char *changeuser, *ch_root, *ch_dir; @@ -167,20 +150,6 @@ static inline int ioprio_set(int which _unused, #endif static void -free_schedulelist(void) -{ - SCHEDULEITEM *s1 = TAILQ_FIRST(&schedule); - SCHEDULEITEM *s2; - - while (s1) { - s2 = TAILQ_NEXT(s1, entries); - free(s1); - s1 = s2; - } - TAILQ_INIT(&schedule); -} - -static void cleanup(void) { free(changeuser); @@ -188,360 +157,6 @@ cleanup(void) free_schedulelist(); } -static int -parse_signal(const char *sig) -{ - typedef struct signalpair - { - const char *name; - int signal; - } SIGNALPAIR; - -#define signalpair_item(name) { #name, SIG##name }, - - static const SIGNALPAIR signallist[] = { - signalpair_item(HUP) - signalpair_item(INT) - signalpair_item(QUIT) - signalpair_item(ILL) - signalpair_item(TRAP) - signalpair_item(ABRT) - signalpair_item(BUS) - signalpair_item(FPE) - signalpair_item(KILL) - signalpair_item(USR1) - signalpair_item(SEGV) - signalpair_item(USR2) - signalpair_item(PIPE) - signalpair_item(ALRM) - signalpair_item(TERM) - signalpair_item(CHLD) - signalpair_item(CONT) - signalpair_item(STOP) - signalpair_item(TSTP) - signalpair_item(TTIN) - signalpair_item(TTOU) - signalpair_item(URG) - signalpair_item(XCPU) - signalpair_item(XFSZ) - signalpair_item(VTALRM) - signalpair_item(PROF) -#ifdef SIGWINCH - signalpair_item(WINCH) -#endif -#ifdef SIGIO - signalpair_item(IO) -#endif -#ifdef SIGPWR - signalpair_item(PWR) -#endif - signalpair_item(SYS) - { "NULL", 0 }, - }; - - unsigned int i = 0; - const char *s; - - if (!sig || *sig == '\0') - return -1; - - if (sscanf(sig, "%u", &i) == 1) { - if (i < NSIG) - return i; - eerrorx("%s: `%s' is not a valid signal", applet, sig); - } - - if (strncmp(sig, "SIG", 3) == 0) - s = sig + 3; - else - s = NULL; - - for (i = 0; i < ARRAY_SIZE(signallist); ++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", applet, sig); - /* NOTREACHED */ -} - -static SCHEDULEITEM * -parse_schedule_item(const char *string) -{ - const char *after_hyph; - int sig; - SCHEDULEITEM *item = xmalloc(sizeof(*item)); - - item->value = 0; - item->gotoitem = NULL; - if (strcmp(string,"forever") == 0) - item->type = SC_FOREVER; - else if (isdigit((unsigned char)string[0])) { - item->type = SC_TIMEOUT; - errno = 0; - if (sscanf(string, "%d", &item->value) != 1) - eerrorx("%s: invalid timeout value in schedule `%s'", - applet, string); - } else if ((after_hyph = string + (string[0] == '-')) && - ((sig = parse_signal(after_hyph)) != -1)) - { - item->type = SC_SIGNAL; - item->value = (int)sig; - } else - eerrorx("%s: invalid schedule item `%s'", applet, string); - - return item; -} - -static void -parse_schedule(const char *string, int timeout) -{ - char buffer[20]; - const char *slash; - int count = 0; - SCHEDULEITEM *repeatat = NULL; - size_t len; - SCHEDULEITEM *item; - - if (string) - for (slash = string; *slash; slash++) - if (*slash == '/') - count++; - - free_schedulelist(); - - if (count == 0) { - item = xmalloc(sizeof(*item)); - item->type = SC_SIGNAL; - item->value = timeout; - item->gotoitem = NULL; - TAILQ_INSERT_TAIL(&schedule, item, entries); - - item = xmalloc(sizeof(*item)); - item->type = SC_TIMEOUT; - item->gotoitem = NULL; - TAILQ_INSERT_TAIL(&schedule, item, entries); - if (string) { - if (sscanf(string, "%d", &item->value) != 1) - eerrorx("%s: invalid timeout in schedule", - applet); - } else - item->value = 5; - - return; - } - - 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", - applet); - - memcpy(buffer, string, len); - buffer[len] = 0; - string = slash ? slash + 1 : NULL; - - item = parse_schedule_item(buffer); - TAILQ_INSERT_TAIL(&schedule, item, entries); - if (item->type == SC_FOREVER) { - if (repeatat) - eerrorx("%s: invalid schedule, `forever' " - "appears more than once", applet); - - repeatat = item; - continue; - } - } - - if (repeatat) { - item = xmalloc(sizeof(*item)); - item->type = SC_GOTO; - item->value = 0; - item->gotoitem = repeatat; - TAILQ_INSERT_TAIL(&schedule, item, entries); - } - - return; -} - -/* return number of processed killed, -1 on error */ -static int -do_stop(const char *exec, const char *const *argv, - pid_t pid, uid_t uid,int sig, bool test) -{ - RC_PIDLIST *pids; - RC_PID *pi; - RC_PID *np; - bool killed; - int nkilled = 0; - - if (pid) - pids = rc_find_pids(NULL, NULL, 0, pid); - else - pids = rc_find_pids(exec, argv, uid, pid); - - if (!pids) - return 0; - - LIST_FOREACH_SAFE(pi, pids, entries, np) { - if (test) { - einfo("Would send signal %d to PID %d", sig, pi->pid); - nkilled++; - } else { - ebeginv("Sending signal %d to PID %d", sig, pi->pid); - errno = 0; - killed = (kill(pi->pid, sig) == 0 || - errno == ESRCH ? true : false); - eendv(killed ? 0 : 1, - "%s: failed to send signal %d to PID %d: %s", - applet, sig, pi->pid, strerror(errno)); - if (!killed) { - nkilled = -1; - } else { - if (nkilled != -1) - nkilled++; - } - } - free(pi); - } - - free(pids); - return nkilled; -} - -static int -run_stop_schedule(const char *exec, const char *const *argv, - const char *pidfile, uid_t uid, - bool test, bool progress) -{ - SCHEDULEITEM *item = TAILQ_FIRST(&schedule); - int nkilled = 0; - int tkilled = 0; - int nrunning = 0; - long nloops, nsecs; - struct timespec ts; - pid_t pid = 0; - const char *const *p; - bool progressed = false; - - if (exec) - einfov("Will stop %s", exec); - if (pidfile) - einfov("Will stop PID in pidfile `%s'", pidfile); - if (uid) - einfov("Will stop processes owned by UID %d", uid); - if (argv && *argv) { - einfovn("Will stop processes of `"); - if (rc_yesno(getenv("EINFO_VERBOSE"))) { - for (p = argv; p && *p; p++) { - if (p != argv) - printf(" "); - printf("%s", *p); - } - printf("'\n"); - } - } - - if (pidfile) { - pid = get_pid(applet, pidfile); - if (pid == -1) - return 0; - } - - while (item) { - switch (item->type) { - case SC_GOTO: - item = item->gotoitem; - continue; - - case SC_SIGNAL: - nrunning = 0; - nkilled = do_stop(exec, argv, pid, uid, item->value, test); - if (nkilled == 0) { - if (tkilled == 0) { - if (progressed) - printf("\n"); - eerror("%s: no matching processes found", applet); - } - return tkilled; - } - else if (nkilled == -1) - return 0; - - tkilled += nkilled; - break; - case SC_TIMEOUT: - if (item->value < 1) { - item = NULL; - break; - } - - ts.tv_sec = 0; - ts.tv_nsec = POLL_INTERVAL; - - for (nsecs = 0; nsecs < item->value; nsecs++) { - for (nloops = 0; - nloops < ONE_SECOND / POLL_INTERVAL; - nloops++) - { - if ((nrunning = do_stop(exec, argv, - pid, uid, 0, test)) == 0) - return 0; - - - if (nanosleep(&ts, NULL) == -1) { - if (progressed) { - printf("\n"); - progressed = false; - } - if (errno == EINTR) - eerror("%s: caught an" - " interrupt", applet); - else { - eerror("%s: nanosleep: %s", - applet, strerror(errno)); - return 0; - } - } - } - if (progress) { - printf("."); - fflush(stdout); - progressed = true; - } - } - break; - default: - if (progressed) { - printf("\n"); - progressed = false; - } - eerror("%s: invalid schedule item `%d'", - applet, item->type); - return 0; - } - - if (item) - item = TAILQ_NEXT(item, entries); - } - - if (test || (tkilled > 0 && nrunning == 0)) - return nkilled; - - if (progressed) - printf("\n"); - if (nrunning == 1) - eerror("%s: %d process refused to stop", applet, nrunning); - else - eerror("%s: %d process(es) refused to stop", applet, nrunning); - - return -nrunning; -} - static void handle_signal(int sig) { @@ -682,7 +297,6 @@ int main(int argc, char **argv) unsigned int start_wait = 0; applet = basename_c(argv[0]); - TAILQ_INIT(&schedule); atexit(cleanup); signal_setup(SIGINT, handle_signal); @@ -851,7 +465,7 @@ int main(int argc, char **argv) break; case 's': /* --signal <signal> */ - sig = parse_signal(optarg); + sig = parse_signal(applet, optarg); break; case 't': /* --test */ @@ -1037,12 +651,12 @@ int main(int argc, char **argv) if (!stop) oknodo = true; if (retry) - parse_schedule(retry, sig); + parse_schedule(applet, retry, sig); else if (test || oknodo) - parse_schedule("0", sig); + parse_schedule(applet, "0", sig); else - parse_schedule(NULL, sig); - i = run_stop_schedule(exec, (const char *const *)margv, + parse_schedule(applet, NULL, sig); + i = run_stop_schedule(applet, exec, (const char *const *)margv, pidfile, uid, test, progress); if (i < 0) @@ -1069,7 +683,7 @@ int main(int argc, char **argv) else pid = 0; - if (do_stop(exec, (const char * const *)margv, pid, uid, + if (do_stop(applet, exec, (const char * const *)margv, pid, uid, 0, test) > 0) eerrorx("%s: %s is already running", applet, exec); @@ -1349,7 +963,7 @@ int main(int argc, char **argv) } } else pid = 0; - if (do_stop(exec, (const char *const *)margv, + if (do_stop(applet, exec, (const char *const *)margv, pid, uid, 0, test) > 0) alive = true; } |