There are many cases where scripts want to make sure that a daemon released their resources properly before continuing. These are e.g. init scripts that want to restart a daemon to apply changes in the configuration.
start-stop-daemon when FEATURE_START_STOP_DAEMON_FANCY is enabled already accepts -R and ignores it. This means that they are already scripts in the wild that uses -R with schedules, even in buildroot. It is thus not possible to only support a subset of -R, like only "-R secs" because that would cause regressions. There are two remaining options: accept -R, ignore its argument and use a hardcoded schedule, or accept all common forms of -R (everything but 'forever' which does not appear to be used anywhere). Parsing -R schedules takes a lot of bytes so this implement both options: _FANCY alone gives -R with a hardcoded schedule of signal/30/KILL/30, while _RETRY_SCHEDULE enables the parser. Like debianutils's start-stop-daemon, this one uses kill(0) to detect gone processes. But it sleeps in 125ms increments instead of using a complicated algorithm that sleeps at least 20ms or using Linux-specific pidfd. With parsing disabled (-R is hardcoded to signal/30/KILL/30): function old new delta start_stop_daemon_main 1327 1353 +26 static.do_kill - 95 +95 packed_usage 34718 34738 +20 check 460 464 +4 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 3/0 up/down: 145/0) Total: 145 bytes With parsing enabled: function old new delta start_stop_daemon_main 1327 1493 +166 static.do_kill - 95 +95 packed_usage 34718 34730 +12 check 460 464 +4 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 3/0 up/down: 277/0) Total: 277 bytes Signed-off-by: Nicolas Cavallari <[email protected]> --- debianutils/start_stop_daemon.c | 152 ++++++++++++++++++++++++++------ 1 file changed, 127 insertions(+), 25 deletions(-) diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c index 271bc4edf..c86a82b3e 100644 --- a/debianutils/start_stop_daemon.c +++ b/debianutils/start_stop_daemon.c @@ -111,6 +111,14 @@ Misc options: //config: -o|--oknodo ignored since we exit with 0 anyway //config: -v|--verbose //config: -N|--nicelevel N +//config: -R|--retry R +//config: +//config:config FEATURE_START_STOP_DAEMON_RETRY_SCHEDULE +//config: bool "Support -R schedules" +//config: depends on FEATURE_START_STOP_DAEMON_FANCY +//config: help +//config: support complex --retry schedules instead of a +//config: hardcoded signal/30/KILL/30 //applet:IF_START_STOP_DAEMON(APPLET_ODDNAME(start-stop-daemon, start_stop_daemon, BB_DIR_SBIN, BB_SUID_DROP, start_stop_daemon)) /* not NOEXEC: uses bb_common_bufsiz1 */ @@ -145,6 +153,14 @@ Misc options: //usage: "\n-K only:" //usage: "\n -s SIG Signal to send" //usage: "\n -t Match only, exit with 0 if found" +//usage: IF_FEATURE_START_STOP_DAEMON_FANCY( +//usage: IF_FEATURE_START_STOP_DAEMON_RETRY_SCHEDULE( +//usage: "\n -R SEC[/SIG/..] Wait until stopped" +//usage: ) +//usage: IF_NOT_FEATURE_START_STOP_DAEMON_RETRY_SCHEDULE( +//usage: "\n -R IGNORED Wait until stopped" +//usage: ) +//usage: ) //usage: "\nOther:" //usage: IF_FEATURE_START_STOP_DAEMON_FANCY( //usage: "\n -o Exit with status 0 if nothing is done" @@ -160,6 +176,9 @@ Misc options: struct pid_list { struct pid_list *next; pid_t pid; +# if ENABLE_FEATURE_START_STOP_DAEMON_FANCY + smallint gone; +#endif }; enum { @@ -194,7 +213,12 @@ struct globals { char *execname_cmpbuf; unsigned execname_sizeof; int user_id; +#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY +#define RETRIES_COUNT 16 + int retries[RETRIES_COUNT]; +#else smallint signal_nr; +#endif #ifdef OLDER_VERSION_OF_X struct stat execstat; #endif @@ -205,7 +229,14 @@ struct globals { #define execname (G.execname ) #define pidfile (G.pidfile ) #define user_id (G.user_id ) + +#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY +#define retries (G.retries ) +#define signal_nr (retries[0] ) +#else #define signal_nr (G.signal_nr ) +#endif + #define INIT_G() do { \ setup_common_bufsiz(); \ user_id = -1; \ @@ -308,6 +339,9 @@ static void check(int pid) p = xmalloc(sizeof(*p)); p->next = G.found_procs; p->pid = pid; +#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY + p->gone = -1; +#endif G.found_procs = p; } @@ -358,6 +392,54 @@ static void do_procinit(void) bb_simple_error_msg_and_die("nothing in /proc - not mounted?"); } +static int do_kill(int sig, int test) +{ + struct pid_list *p; + int killed = 0; + + for (p = G.found_procs; p; p = p->next) { +#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY + if (p->gone > 0) + continue; +#endif + if (kill(p->pid, sig) == 0) { + killed++; + } else { + if (sig) + bb_perror_msg("warning: killing process %u", (unsigned)p->pid); +#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY + p->gone = !sig; +#else + p->pid = 0; +#endif + if (test) { + /* Example: -K --test --pidfile PIDFILE detected + * that PIDFILE's pid doesn't exist */ + return -1; + } + } + } + return killed; +} + +#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY +static int do_stop_schedule(void) { + int killed = 0; + int *action = &retries[0]; + while (*action) { + if (*action > 0) { + killed += do_kill(*action, 0); + } else { + msleep(125); + if (do_kill(0, 0) && ++(*action)) + continue; + } + action++; + } + return killed; +} +#endif + static int do_stop(void) { const char *what; @@ -384,24 +466,19 @@ static int do_stop(void) killed = -1; goto ret; } - for (p = G.found_procs; p; p = p->next) { - if (kill(p->pid, TEST ? 0 : signal_nr) == 0) { - killed++; - } else { - bb_perror_msg("warning: killing process %u", (unsigned)p->pid); - p->pid = 0; - if (TEST) { - /* Example: -K --test --pidfile PIDFILE detected - * that PIDFILE's pid doesn't exist */ - killed = -1; - goto ret; - } - } - } - if (!QUIET && killed) { +#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY + killed = do_stop_schedule(); +#else + killed = do_kill(TEST ? 0 : signal_nr, TEST); +#endif + if (!QUIET && killed > 0) { printf("stopped %s (pid", what); for (p = G.found_procs; p; p = p->next) +#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY + if (p->gone) +#else if (p->pid) +#endif printf(" %u", (unsigned)p->pid); puts(")"); } @@ -453,9 +530,9 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) char *chuid; const char *chdir; const char *output = NULL; + int i = 0; #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY -// const char *retry_arg = NULL; -// int retries = -1; + char *retry_arg = NULL; const char *opt_N; #endif @@ -479,9 +556,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) , LONGOPTS &startas, &cmdname, &signame, &userspec, &chuid, &chdir, &execname, &pidfile, &output - IF_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N) - /* We accept and ignore -R <param> / --retry <param> */ - IF_FEATURE_START_STOP_DAEMON_FANCY(,NULL) + IF_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N, &retry_arg) ); //-O requires --background and absolute pathname (tested with 1.21.22). @@ -523,10 +598,37 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) G.execname_sizeof = strlen(execname) + 1; G.execname_cmpbuf = xmalloc(G.execname_sizeof + 1); } -// IF_FEATURE_START_STOP_DAEMON_FANCY( -// if (retry_arg) -// retries = xatoi_positive(retry_arg); -// ) +#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY + if (retry_arg) { +#if ENABLE_FEATURE_START_STOP_DAEMON_RETRY_SCHEDULE + char *first_strtok_arg = retry_arg; + int signal = signal_nr; + int act_value; + const char *action; + + while ((action = strtok_r(first_strtok_arg, "/", &retry_arg)) + && i < RETRIES_COUNT - 1) { + if (isdigit(action[0])) { + act_value = -8 * xatoi_positive(action); + } else { + act_value = get_signum(action + (action[0] == '-')); + if (act_value < 0) + bb_error_msg_and_die("unknown signal '%s'", action); + } + retries[i++] = act_value; + first_strtok_arg = NULL; + } + if (i == 1) { + retries[1] = retries[3] = retries[0]; + retries[0] = signal; + retries[2] = SIGKILL; + } +#else + retries[1] = retries[3] = -30*8; + retries[2] = SIGKILL; +#endif + } +#endif if (userspec) { user_id = bb_strtou(userspec, NULL, 10); if (errno) @@ -537,7 +639,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) do_procinit(); if (opt & CTX_STOP) { - int i = do_stop(); + i = do_stop(); return (opt & OPT_OKNODO) ? 0 : (i <= 0); } -- 2.51.0 _______________________________________________ busybox mailing list [email protected] https://lists.busybox.net/mailman/listinfo/busybox
