service: give stop and reload scripts their own timeout

Both were bounded by killdelay, the delay between the stop signal and
SIGKILL, because service_run_script() had nothing else to reach for.
That conflates two things: how long the daemon may take to die, and
how long its stop script may run.

Give each hook a timeout of its own, defaulting to killdelay when
unset, so the existing behaviour is what you get until you ask for
something else.  parse_script() already falls back that way for the
hooks that had one.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg
2026-07-30 15:21:27 +02:00
parent 2a5190ecff
commit 53cb2b7bdb
2 changed files with 8 additions and 6 deletions
+6 -6
View File
@@ -1076,7 +1076,7 @@ static void service_kill(svc_t *svc)
* Called by service_stop() and service_reload() when alternate mechanisms
* for stopping and reloading have been specified by the user.
*/
static int service_run_script(svc_t *svc, char *script)
static int service_run_script(svc_t *svc, char *script, int tmo)
{
const char *id = svc_ident(svc, NULL, 0);
pid_t pid = service_fork(svc);
@@ -1106,7 +1106,7 @@ static int service_run_script(svc_t *svc, char *script)
}
dbg("%s: script '%s' started as PID %d", id, script, pid);
return service_script_add(svc, pid, svc->killdelay);
return service_script_add(svc, pid, tmo ? tmo : svc->killdelay);
}
/* Ensure we don't have any notify socket lingering */
@@ -1268,7 +1268,7 @@ int service_stop(svc_t *svc)
print_desc("Stopping ", svc->desc);
if (svc->stop_script[0]) {
rc = service_run_script(svc, svc->stop_script);
rc = service_run_script(svc, svc->stop_script, svc->stop_tmo);
} else if (!svc_is_sysv(svc)) {
if (svc->pid > 1) {
/*
@@ -1360,7 +1360,7 @@ static int service_reload(svc_t *svc)
if (svc->reload_script[0]) {
logit(LOG_CONSOLE | LOG_NOTICE, "Reloading %s[%d], calling reload:%s ...", id, svc->pid, svc->reload_script);
rc = service_run_script(svc, svc->reload_script);
rc = service_run_script(svc, svc->reload_script, svc->reload_tmo);
} else if (svc->sighup) {
if (svc->pid <= 1) {
dbg("%s[%d]: bad PID, cannot reload service", id, svc->pid);
@@ -2211,12 +2211,12 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
memset(svc->cleanup_script, 0, sizeof(svc->cleanup_script));
if (reload_script)
parse_script(svc, "reload", reload_script, NULL, svc->reload_script, sizeof(svc->reload_script));
parse_script(svc, "reload", reload_script, &svc->reload_tmo, svc->reload_script, sizeof(svc->reload_script));
else
memset(svc->reload_script, 0, sizeof(svc->reload_script));
if (stop_script)
parse_script(svc, "stop", stop_script, NULL, svc->stop_script, sizeof(svc->stop_script));
parse_script(svc, "stop", stop_script, &svc->stop_tmo, svc->stop_script, sizeof(svc->stop_script));
else
memset(svc->stop_script, 0, sizeof(svc->stop_script));
+2
View File
@@ -221,9 +221,11 @@ typedef struct svc {
/* When set, used instead of SIGHUP or stop-start */
char reload_script[MAX_CMD_LEN];
int reload_tmo;
/* When set, used instead of SIGTERM or sysv 'stop' */
char stop_script[MAX_CMD_LEN];
int stop_tmo;
/*
* Used to forcefully kill services that won't shutdown on