Add reload:'script [args]' support for service/sysv stanzas

Fixes #446

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg
2025-07-06 12:05:51 +02:00
parent 7ad802b092
commit 57545e1ab0
2 changed files with 48 additions and 28 deletions
+44 -26
View File
@@ -1120,34 +1120,27 @@ int service_stop(svc_t *svc)
}
/**
* service_restart - Restart a service by sending %SIGHUP
* service_reload - Reload a service
* @svc: Service to reload
*
* This function does some basic checks of the runtime state of Finit
* and a sanity check of the @svc before sending %SIGHUP.
* and a sanity check of the @svc before sending %SIGHUP or calling
* the reload:script command.
*
* Returns:
* POSIX OK(0) or non-zero on error.
*/
static int service_restart(svc_t *svc)
static int service_reload(svc_t *svc)
{
const char *id = svc_ident(svc, NULL, 0);
int do_progress = 1;
pid_t lost = 0;
int rc;
/* Ignore if finit is SIGSTOP'ed */
if (is_norespawn())
/* Ignore if service is invalid or finit is SIGSTOP'ed */
if (!svc || is_norespawn())
return 1;
if (!svc || !svc->sighup)
return 1;
if (svc->pid <= 1) {
dbg("%s: bad PID %d for %s, SIGHUP", svc_ident(svc, NULL, 0), svc->pid, svc->cmd);
svc->start_time = svc->pid = 0;
return 1;
}
/* Skip progress if desc disabled or bootstrap task */
if (!svc->desc[0] || svc_in_runlevel(svc, INIT_LEVEL))
do_progress = 0;
@@ -1155,14 +1148,28 @@ static int service_restart(svc_t *svc)
if (do_progress)
print_desc("Restarting ", svc->desc);
dbg("Sending SIGHUP to PID %d", svc->pid);
logit(LOG_CONSOLE | LOG_NOTICE, "Restarting %s[%d], sending SIGHUP ...",
svc_ident(svc, NULL, 0), svc->pid);
rc = kill(svc->pid, SIGHUP);
if (rc == -1 && (errno == ESRCH || errno == ENOENT)) {
/* nobody home, reset internal state machine */
lost = svc->pid;
if (svc->reload_script[0]) {
logit(LOG_CONSOLE | LOG_NOTICE, "%s[%d], calling %s ...", id, svc->pid, svc->reload_script);
rc = run(svc->reload_script, NULL);
} else if (svc->sighup) {
if (svc->pid <= 1) {
dbg("%s[%d]: bad PID, cannot reload service", id, svc->pid);
svc->start_time = svc->pid = 0;
goto done;
}
dbg("%s[%d], sending SIGHUP", id, svc->pid);
logit(LOG_CONSOLE | LOG_NOTICE, "%s[%d], sending SIGHUP ...", id, svc->pid);
rc = kill(svc->pid, SIGHUP);
if (rc == -1 && (errno == ESRCH || errno == ENOENT)) {
/* nobody home, reset internal state machine */
lost = svc->pid;
}
} else {
warnx("%s: neither HUP nor reload:script defined, no action.", id);
rc = 1;
}
if (!rc) {
/* Declare we're waiting for svc to re-assert/touch its pidfile */
svc_starting(svc);
@@ -1172,7 +1179,7 @@ static int service_restart(svc_t *svc)
touch(pid_file(svc));
}
}
done:
if (do_progress)
print_result(rc);
@@ -1601,7 +1608,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
char *id = NULL, *env = NULL, *cgroup = NULL;
char *pre_script = NULL, *post_script = NULL;
char *ready_script = NULL, *conflict = NULL;
char *cleanup_script = NULL;
char *reload_script = NULL, *cleanup_script = NULL;
char ident[MAX_IDENT_LEN];
char *ifstmt = NULL;
char *notify = NULL;
@@ -1711,6 +1718,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
ready_script = arg;
else if (MATCH_CMD(cmd, "cleanup:", arg))
cleanup_script = arg;
else if (MATCH_CMD(cmd, "reload:", arg))
reload_script = arg;
else if (MATCH_CMD(cmd, "env:", arg))
env = arg;
/* catch both cgroup: and cgroup. handled in parse_cgroup() */
@@ -1906,6 +1915,11 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
else
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));
else
memset(svc->reload_script, 0, sizeof(svc->reload_script));
if (!svc_is_tty(svc)) {
if (log)
parse_log(svc, log);
@@ -2151,7 +2165,7 @@ void service_update_rdeps(void)
continue;
/* Service supports reloading conf without stop/start */
if (!svc_is_nohup(svc))
if (!svc_is_noreload(svc))
continue; /* Yup, no need to stop start rdeps */
svc_mark_affected(mkcond(svc, cond, sizeof(cond)));
@@ -2786,7 +2800,11 @@ restart:
case COND_ON:
if (svc_is_changed(svc)) {
if (svc_nohup(svc) || !svc_is_daemon(svc)) {
/*
* If service does not suport reload, or its command line
* arguments have been modified, we need to stop-start it.
*/
if (svc_is_noreload(svc) || svc->args_dirty) {
service_stop(svc);
} else {
/*
@@ -2796,7 +2814,7 @@ restart:
if (sm_in_reload())
break;
service_restart(svc);
service_reload(svc);
}
svc_mark_clean(svc);
+4 -2
View File
@@ -212,6 +212,9 @@ typedef struct svc {
char cleanup_script[MAX_CMD_LEN];
int cleanup_tmo;
/* When set, used instead of SIGHUP or stop-start */
char reload_script[MAX_CMD_LEN];
/*
* Used to forcefully kill services that won't shutdown on
* termination and to delay restarts of crashing services.
@@ -272,10 +275,9 @@ static inline int svc_is_tty (svc_t *svc) { return svc && SVC_TYPE_TTY
static inline int svc_is_runtask (svc_t *svc) { return svc && (SVC_TYPE_RUNTASK & svc->type);}
static inline int svc_is_forking (svc_t *svc) { return svc && svc->forking; }
static inline int svc_is_manual (svc_t *svc) { return svc && svc->manual; }
static inline int svc_is_nohup (svc_t *svc) { return svc && (0 == svc->sighup); }
static inline int svc_is_noreload (svc_t *svc) { return svc && (0 == svc->sighup && 0 == svc->reload_script[0]); }
static inline int svc_in_runlevel (svc_t *svc, int runlevel) { return svc && ISSET(svc->runlevels, runlevel); }
static inline int svc_nohup (svc_t *svc) { return svc && (0 == svc->sighup || 0 != svc->args_dirty); }
static inline int svc_has_pidfile (svc_t *svc) { return svc_is_daemon(svc) && svc->pidfile[0] != 0 && svc->pidfile[0] != '!'; }
static inline int svc_has_pre (svc_t *svc) { return svc->pre_script[0]; }
static inline int svc_has_post (svc_t *svc) { return svc->post_script[0]; }