From abcb3ceb67621461b559bd06e28d58a6fbbcbec9 Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Tue, 23 Aug 2022 09:37:18 +0200 Subject: [PATCH] Fix #300: add ready:script for services, called when daemon is ready In Finit a daemon can signal its readiness by creating/touching its PID file. An ancient UNIX concept -- a daemon creates its PID file when it has set up signal handlers and is ready to receive IPC (signals), right before entering its while(1) loop. Finit took the concept a bit further, adding readiness signalling also to daemon's by touching their PID file after having processed a SIGHUP. For both these conditions Finit now supports a ready:script, called when readiness is detected. In later commits support for s6 and systemd style readiness notification will be added that will hook the mechanism implemented in this commit as well. Signed-off-by: Joachim Wiberg --- src/cond-w.c | 7 +++++++ src/service.c | 45 ++++++++++++++++++++++++++++++++++++++++++++- src/service.h | 2 ++ src/svc.h | 2 ++ 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/cond-w.c b/src/cond-w.c index cd127cce..e4525fed 100644 --- a/src/cond-w.c +++ b/src/cond-w.c @@ -297,10 +297,17 @@ int cond_set_noupdate(const char *name) void cond_set(const char *name) { + svc_t *svc; + _d("%s", name); if (cond_set_noupdate(name)) return; + /* XXX: refactor when new notify framework is in place */ + svc = svc_find_by_cond(name); + if (svc && svc_has_ready(svc)) + service_ready_script(svc); + cond_update(name); } diff --git a/src/service.c b/src/service.c index 3d678d4e..99c0687d 100644 --- a/src/service.c +++ b/src/service.c @@ -1266,6 +1266,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) char *name = NULL, *halt = NULL, *delay = NULL; char *id = NULL, *env = NULL, *cgroup = NULL; char *pre_script = NULL, *post_script = NULL; + char *ready_script = NULL; struct tty tty = { 0 }; char *dev = NULL; int respawn = 0; @@ -1361,6 +1362,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) pre_script = arg; else if (MATCH_CMD(cmd, "post:", arg)) post_script = arg; + else if (MATCH_CMD(cmd, "ready:", arg)) + ready_script = arg; else if (MATCH_CMD(cmd, "env:", arg)) env = arg; else if (MATCH_CMD(cmd, "cgroup:", arg)) @@ -1516,6 +1519,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) parse_script("pre", pre_script, svc->pre_script, sizeof(svc->pre_script)); if (post_script) parse_script("post", post_script, svc->post_script, sizeof(svc->post_script)); + if (ready_script) + parse_script("ready", ready_script, svc->ready_script, sizeof(svc->ready_script)); if (log) parse_log(svc, log); if (desc) @@ -1607,7 +1612,8 @@ void service_monitor(pid_t lost, int status) svc = svc_find_by_pid(lost); if (!svc) { - _d("collected unknown PID %d", lost); + if (service_script_del(lost)) + _d("collected unknown PID %d", lost); return; } @@ -1805,6 +1811,43 @@ static void service_post_script(svc_t *svc) service_timeout_after(svc, svc->killdelay, service_kill_script); } +void service_ready_script(svc_t *svc) +{ + pid_t pid; + + if (access(svc->ready_script, X_OK)) + return; + + pid = service_fork(svc); + if (pid < 0) { + _pe("Failed forking off %s ready-script %s", svc_ident(svc, NULL, 0), svc->ready_script); + return; + } + + if (pid == 0) { + char buf[CMD_SIZE]; + char *argv[4] = { + "sh", + "-ac", + buf, + NULL + }; + char *env_file; + + env_file = svc_getenv(svc); + if (env_file) + snprintf(buf, sizeof(buf), ". %s; exec %s", env_file, svc->ready_script); + else + strlcpy(buf, svc->ready_script, sizeof(buf)); + + set_pre_post_envs(svc, "ready"); + execvp(_PATH_BSHELL, argv); + _exit(EX_OSERR); + } + + service_script_add(svc, pid); +} + static void service_retry(svc_t *svc) { char *restart_cnt = (char *)&svc->restart_cnt; diff --git a/src/service.h b/src/service.h index 9831ea05..ba33a834 100644 --- a/src/service.h +++ b/src/service.h @@ -35,6 +35,8 @@ void service_runtask_clean (void); void service_reload_dynamic (void); void service_update_rdeps (void); +void service_ready_script (svc_t *svc); /* XXX: only for pidfile plugin before notify framework */ + int service_timeout_after (svc_t *svc, int timeout, void (*cb)(svc_t *svc)); int service_timeout_cancel (svc_t *svc); diff --git a/src/svc.h b/src/svc.h index ac787968..3b000c70 100644 --- a/src/svc.h +++ b/src/svc.h @@ -183,6 +183,7 @@ typedef struct svc { char env[MAX_ARG_LEN]; char pre_script[MAX_ARG_LEN]; char post_script[MAX_ARG_LEN]; + char ready_script[MAX_ARG_LEN]; /* * Used to forcefully kill services that won't shutdown on @@ -239,6 +240,7 @@ static inline int svc_nohup (svc_t *svc) { return svc && (0 == svc->sigh 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]; } +static inline int svc_has_ready (svc_t *svc) { return svc->ready_script[0];} static inline void svc_starting (svc_t *svc) { if (svc) svc->starting = 1; } static inline void svc_started (svc_t *svc) { if (svc) svc->starting = 0; }