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 * @svc: Service to reload
* *
* This function does some basic checks of the runtime state of Finit * 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: * Returns:
* POSIX OK(0) or non-zero on error. * 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; int do_progress = 1;
pid_t lost = 0; pid_t lost = 0;
int rc; int rc;
/* Ignore if finit is SIGSTOP'ed */ /* Ignore if service is invalid or finit is SIGSTOP'ed */
if (is_norespawn()) if (!svc || is_norespawn())
return 1; 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 */ /* Skip progress if desc disabled or bootstrap task */
if (!svc->desc[0] || svc_in_runlevel(svc, INIT_LEVEL)) if (!svc->desc[0] || svc_in_runlevel(svc, INIT_LEVEL))
do_progress = 0; do_progress = 0;
@@ -1155,14 +1148,28 @@ static int service_restart(svc_t *svc)
if (do_progress) if (do_progress)
print_desc("Restarting ", svc->desc); print_desc("Restarting ", svc->desc);
dbg("Sending SIGHUP to PID %d", svc->pid); if (svc->reload_script[0]) {
logit(LOG_CONSOLE | LOG_NOTICE, "Restarting %s[%d], sending SIGHUP ...", logit(LOG_CONSOLE | LOG_NOTICE, "%s[%d], calling %s ...", id, svc->pid, svc->reload_script);
svc_ident(svc, NULL, 0), svc->pid); rc = run(svc->reload_script, NULL);
rc = kill(svc->pid, SIGHUP); } else if (svc->sighup) {
if (rc == -1 && (errno == ESRCH || errno == ENOENT)) { if (svc->pid <= 1) {
/* nobody home, reset internal state machine */ dbg("%s[%d]: bad PID, cannot reload service", id, svc->pid);
lost = 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 { } 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 */ /* Declare we're waiting for svc to re-assert/touch its pidfile */
svc_starting(svc); svc_starting(svc);
@@ -1172,7 +1179,7 @@ static int service_restart(svc_t *svc)
touch(pid_file(svc)); touch(pid_file(svc));
} }
} }
done:
if (do_progress) if (do_progress)
print_result(rc); 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 *id = NULL, *env = NULL, *cgroup = NULL;
char *pre_script = NULL, *post_script = NULL; char *pre_script = NULL, *post_script = NULL;
char *ready_script = NULL, *conflict = NULL; char *ready_script = NULL, *conflict = NULL;
char *cleanup_script = NULL; char *reload_script = NULL, *cleanup_script = NULL;
char ident[MAX_IDENT_LEN]; char ident[MAX_IDENT_LEN];
char *ifstmt = NULL; char *ifstmt = NULL;
char *notify = NULL; char *notify = NULL;
@@ -1711,6 +1718,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
ready_script = arg; ready_script = arg;
else if (MATCH_CMD(cmd, "cleanup:", arg)) else if (MATCH_CMD(cmd, "cleanup:", arg))
cleanup_script = arg; cleanup_script = arg;
else if (MATCH_CMD(cmd, "reload:", arg))
reload_script = arg;
else if (MATCH_CMD(cmd, "env:", arg)) else if (MATCH_CMD(cmd, "env:", arg))
env = arg; env = arg;
/* catch both cgroup: and cgroup. handled in parse_cgroup() */ /* 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 else
memset(svc->cleanup_script, 0, sizeof(svc->cleanup_script)); 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 (!svc_is_tty(svc)) {
if (log) if (log)
parse_log(svc, log); parse_log(svc, log);
@@ -2151,7 +2165,7 @@ void service_update_rdeps(void)
continue; continue;
/* Service supports reloading conf without stop/start */ /* 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 */ continue; /* Yup, no need to stop start rdeps */
svc_mark_affected(mkcond(svc, cond, sizeof(cond))); svc_mark_affected(mkcond(svc, cond, sizeof(cond)));
@@ -2786,7 +2800,11 @@ restart:
case COND_ON: case COND_ON:
if (svc_is_changed(svc)) { 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); service_stop(svc);
} else { } else {
/* /*
@@ -2796,7 +2814,7 @@ restart:
if (sm_in_reload()) if (sm_in_reload())
break; break;
service_restart(svc); service_reload(svc);
} }
svc_mark_clean(svc); svc_mark_clean(svc);
+4 -2
View File
@@ -212,6 +212,9 @@ typedef struct svc {
char cleanup_script[MAX_CMD_LEN]; char cleanup_script[MAX_CMD_LEN];
int cleanup_tmo; 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 * Used to forcefully kill services that won't shutdown on
* termination and to delay restarts of crashing services. * 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_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_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_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_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_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_pre (svc_t *svc) { return svc->pre_script[0]; }
static inline int svc_has_post (svc_t *svc) { return svc->post_script[0]; } static inline int svc_has_post (svc_t *svc) { return svc->post_script[0]; }