From 17b5cc78d35dc5fe4904e5951715c3e0d07d6343 Mon Sep 17 00:00:00 2001 From: William Hubbs Date: Wed, 6 Sep 2017 13:22:30 -0500 Subject: [PATCH] add retry option to supervise-daemon The --retry option for supervise-daemon defines how the supervisor will attempt to stop the child process it is monitoring. It is defined when the supervisor is started since stopping the supervisor just sends a signal to the active supervisor. This fixes #160. --- man/supervise-daemon.8 | 5 +++++ sh/supervise-daemon.sh | 1 + src/rc/Makefile | 2 +- src/rc/supervise-daemon.c | 26 +++++++++++++++++++++++--- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/man/supervise-daemon.8 b/man/supervise-daemon.8 index 34a4e936..0d34a249 100644 --- a/man/supervise-daemon.8 +++ b/man/supervise-daemon.8 @@ -36,6 +36,8 @@ .Ar pidfile .Fl P , -respawn-period .Ar seconds +.Fl R , -retry +.Ar arg .Fl r , -chroot .Ar chrootpath .Fl u , -user @@ -115,6 +117,9 @@ Modifies the scheduling priority of the daemon. .It Fl P , -respawn-period Ar seconds Sets the length of a respawn period. The default is 10 seconds. See the description of --respawn-max for more information. +.It Fl R , -retry Ar timeout | Ar signal Ns / Ns Ar timeout +The retry specification can be either a timeout in seconds or multiple +signal/timeout pairs (like SIGTERM/5). .It Fl r , -chroot Ar path chroot to this directory before starting the daemon. All other paths, such as the path to the daemon, chdir and pidfile, should be relative to the chroot. diff --git a/sh/supervise-daemon.sh b/sh/supervise-daemon.sh index 8add2147..1c1b840d 100644 --- a/sh/supervise-daemon.sh +++ b/sh/supervise-daemon.sh @@ -23,6 +23,7 @@ supervise_start() # command_args="this \"is a\" test" # to work properly. eval supervise-daemon --start \ + ${retry:+--retry} $retry \ ${chroot:+--chroot} $chroot \ ${pidfile:+--pidfile} $pidfile \ ${respawn_delay:+--respawn-delay} $respawn_delay \ diff --git a/src/rc/Makefile b/src/rc/Makefile index e6c9f4a2..a2c7c306 100644 --- a/src/rc/Makefile +++ b/src/rc/Makefile @@ -159,7 +159,7 @@ rc-update: rc-update.o _usage.o rc-misc.o start-stop-daemon: start-stop-daemon.o _usage.o rc-misc.o rc-schedules.o ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} -supervise-daemon: supervise-daemon.o _usage.o rc-misc.o +supervise-daemon: supervise-daemon.o _usage.o rc-misc.o rc-schedules.o ${CC} ${LOCAL_CFLAGS} ${LOCAL_LDFLAGS} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${LDADD} service_get_value service_set_value get_options save_options: do_value.o rc-misc.o diff --git a/src/rc/supervise-daemon.c b/src/rc/supervise-daemon.c index c59fb099..3923dab5 100644 --- a/src/rc/supervise-daemon.c +++ b/src/rc/supervise-daemon.c @@ -61,12 +61,13 @@ 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" const char *applet = NULL; const char *extraopts = NULL; -const char *getoptstring = "D:d:e:g:I:Kk:m:N:p:r:Su:1:2:" \ +const char *getoptstring = "D:d:e:g:I:Kk:m:N:p:R:r:Su:1:2:" \ getoptstring_COMMON; const struct option longopts[] = { { "respawn-delay", 1, NULL, 'D'}, @@ -80,6 +81,7 @@ const struct option longopts[] = { { "nicelevel", 1, NULL, 'N'}, { "pidfile", 1, NULL, 'p'}, { "respawn-period", 1, NULL, 'P'}, + { "retry", 1, NULL, 'R'}, { "chroot", 1, NULL, 'r'}, { "start", 0, NULL, 'S'}, { "user", 1, NULL, 'u'}, @@ -99,6 +101,7 @@ const char * const longopts_help[] = { "Set a nicelevel when starting", "Match pid found in this file", "Set respawn time period", + "Retry schedule to use when stopping", "Chroot to this directory", "Start daemon", "Change the process user", @@ -410,6 +413,9 @@ int main(int argc, char **argv) bool stop = false; char *exec = NULL; char *pidfile = NULL; + char *retry = NULL; + int nkilled; + int sig = SIGTERM; char *home = NULL; int tid = 0; pid_t child_pid, pid; @@ -534,6 +540,9 @@ int main(int argc, char **argv) pidfile = optarg; break; + case 'R': /* --retry |timeout */ + retry = optarg; + break; case 'r': /* --chroot /new/root */ ch_root = optarg; break; @@ -605,6 +614,10 @@ int main(int argc, char **argv) "than %d to avoid infinite respawning", applet, respawn_delay * respawn_max); } + if (retry) + parse_schedule(applet, retry, sig); + else + parse_schedule(applet, NULL, sig); } /* Expand ~ */ @@ -655,9 +668,13 @@ int main(int argc, char **argv) else i = kill(pid, SIGTERM); if (i != 0) - /* We failed to stop something */ + /* We failed to send the signal */ exit(EXIT_FAILURE); + /* wait for the supervisor to go down */ + while (kill(pid, 0) == 0) + sleep(1); + /* Even if we have not actually killed anything, we should * remove information about it as it may have unexpectedly * crashed out. We should also return success as the end @@ -737,7 +754,10 @@ int main(int argc, char **argv) wait(&i); if (exiting) { syslog(LOG_INFO, "stopping %s, pid %d", exec, child_pid); - kill(child_pid, SIGTERM); + nkilled = run_stop_schedule(applet, exec, NULL, child_pid, + 0, false, false); + if (nkilled > 0) + syslog(LOG_INFO, "killed %d processes", nkilled); } else { sleep(respawn_delay); if (respawn_max > 0 && respawn_period > 0) {