diff --git a/doc/config.md b/doc/config.md index ce13a974..808e7d39 100644 --- a/doc/config.md +++ b/doc/config.md @@ -356,17 +356,31 @@ most notably systemd and s6, other methods for signaling "readiness" arrived and daemons were adapted to these new schemes to a larger extent. -As of Finit v4.4 partial support for systemd and s6 is available. The -native PID file mode of operation is still default, the other's can be -defined per service, like this: +As of Finit v4.4 partial support for systemd and s6 style readiness +notification is available, and the native PID file mode of operation is, +as of Finit v4.6 optional, by default it is still enabled, but this can +be changed in `finit.conf`: + readiness none + +This will be made the default in Finit 5.0. In this mode of operation, +every service needs to explicitly declare their readiness notification, +like this: + + service notify:pid watchdogd service notify:systemd foo service notify:s6 bar + service notify:none qux + +The `notify:none` syntax is for completeness in systems which run in +`readiness pid` mode (default). Services declared with `notify:none` +will assert ready condition as soon as Finit has started them, e.g., +`service/qux/ready`. To synchronize two services the following condition can be used: - service notify:systemd A - service B + service notify:pid watchdogd + service stress-ng --cpu 8 For details on the syntax and options, see below. diff --git a/plugins/dbus.c b/plugins/dbus.c index 1161ddbc..08911041 100644 --- a/plugins/dbus.c +++ b/plugins/dbus.c @@ -150,11 +150,11 @@ static void setup(void *arg) * Note: dbus drops privs after starting up. */ if (pidfn) { - snprintf(line, sizeof(line), "[S123456789] cgroup.system name:dbus pid:!%s %s %s -- %s", + snprintf(line, sizeof(line), "[S123456789] cgroup.system notify:none name:dbus pid:!%s %s %s -- %s", pidfn, cmd, DBUS_ARGS, DBUS_DESC); free(pidfn); } else - snprintf(line, sizeof(line), "[S123456789] cgroup.system name:dbus %s %s -- %s", + snprintf(line, sizeof(line), "[S123456789] cgroup.system notify:none name:dbus %s %s -- %s", cmd, DBUS_ARGS, DBUS_DESC); conf_save_service(SVC_TYPE_SERVICE, line, "dbus.conf"); diff --git a/plugins/pidfile.c b/plugins/pidfile.c index 11a80590..dc511047 100644 --- a/plugins/pidfile.c +++ b/plugins/pidfile.c @@ -88,7 +88,7 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask) * systemd style services rely on their respective * readiness notification. Issue #343 */ - if (!svc->notify) + if (svc->notify == SVC_NOTIFY_PID) svc_started(svc); if (!svc_has_pidfile(svc)) { @@ -121,11 +121,11 @@ static void pidfile_update_conds(char *dir, char *name, uint32_t mask) } cond_set(cond); - if (!svc->notify) + if (svc->notify == SVC_NOTIFY_PID) service_ready(svc); } else if (mask & IN_DELETE) { cond_clear(cond); - if (!svc->notify) + if (svc->notify == SVC_NOTIFY_PID) service_ready(svc); } } @@ -240,7 +240,7 @@ static void pidfile_reconf(void *arg) if (svc_is_changed(svc) || svc_is_starting(svc)) continue; - if (!svc->notify) + if (svc->notify == SVC_NOTIFY_PID) service_ready(svc); mkcond(svc, cond, sizeof(cond)); diff --git a/src/conf.c b/src/conf.c index e57a5503..3cefbd0f 100644 --- a/src/conf.c +++ b/src/conf.c @@ -958,6 +958,18 @@ static int parse_static(char *line, int is_rcsd) return 0; } + /* + * Before Finit 5 the default readiness notification is PID. + * This default can be changed by setting 'readiness none' in + * the file /etc/finit.conf, only read once at bootstrap. + */ + if (BOOTSTRAP && MATCH_CMD(line, "readiness ", x)) { + char *token = strip_line(x); + + if (!strcmp(token, "none")) + readiness = SVC_NOTIFY_NONE; + } + if (MATCH_CMD(line, "reboot-delay ", x)) { syncsec = strtonum(strip_line(x), 0, 60, NULL); return 0; @@ -1579,7 +1591,7 @@ int conf_init(uev_ctx_t *ctx) */ #ifdef WDT_DEVNODE if (whichp(FINIT_EXECPATH_ "/watchdogd") && fexist(WDT_DEVNODE)) { - conf_save_service(SVC_TYPE_SERVICE, "[S0123456789] cgroup.init name:watchdog :finit " + conf_save_service(SVC_TYPE_SERVICE, "[S0123456789] cgroup.init notify:none name:watchdog :finit " FINIT_EXECPATH_ "/watchdogd -- Finit watchdog daemon", "watchdogd.conf"); } #endif @@ -1587,7 +1599,7 @@ int conf_init(uev_ctx_t *ctx) * Start kernel event daemon as soon as possible, if enabled */ if (whichp(FINIT_EXECPATH_ "/keventd")) - conf_save_service(SVC_TYPE_SERVICE, "[S0123456789] cgroup.init " + conf_save_service(SVC_TYPE_SERVICE, "[S0123456789] cgroup.init notify:none " FINIT_EXECPATH_ "/keventd -- Finit kernel event daemon", "keventd.conf"); dbg("Allow plugins to register early runlevel 1 run/task/services ..."); @@ -1621,7 +1633,7 @@ int conf_init(uev_ctx_t *ctx) if (runparts_sysv) strlcat(args, "-s ", sizeof(args)); - snprintf(conf, sizeof(conf), "[S] log:console %s %s %s" + snprintf(conf, sizeof(conf), "[S] notify:none log:console %s %s %s" " -- Calling runparts %s in the background", _PATH_RUNPARTS, args, runparts, runparts); conf_save_service(SVC_TYPE_TASK, conf, "runparts.conf"); diff --git a/src/finit.c b/src/finit.c index d3d0bd25..5f8c2598 100644 --- a/src/finit.c +++ b/src/finit.c @@ -69,6 +69,7 @@ int single = 0; /* single user mode from kernel cmdline */ int bootstrap = 1; /* set while bootrapping (for TTYs) */ int kerndebug = 0; /* set if /proc/sys/kernel/printk > 7 */ int syncsec = 0; /* reboot delay */ +int readiness = SVC_NOTIFY_PID; char *finit_conf= NULL; char *finit_rcsd= NULL; char *fstab = NULL; diff --git a/src/finit.h b/src/finit.h index 02f29be1..99423ef7 100644 --- a/src/finit.h +++ b/src/finit.h @@ -121,6 +121,7 @@ extern int single; extern int bootstrap; extern int kerndebug; extern int syncsec; +extern int readiness; extern char *fstab; extern char *sdown; extern char *network; diff --git a/src/service.c b/src/service.c index d3513b78..30f7ffe0 100644 --- a/src/service.c +++ b/src/service.c @@ -701,11 +701,12 @@ static int service_start(svc_t *svc) wordexp_t we = { 0 }; int rc; - if (svc->notify) { + if (svc->notify == SVC_NOTIFY_SYSTEMD || svc->notify == SVC_NOTIFY_S6) { if (client_command(INIT_CMD_NOTIFY_SOCKET)) { err(1, "%s: failed creating notify socket", svc_ident(svc, NULL, 0)); client_disconnect(); - svc->notify = 0; /* does not change parent, restarting may work. */ + /* does not change parent, restarting may work. */ + svc->notify = SVC_NOTIFY_NONE; } else { char val[20]; @@ -730,7 +731,7 @@ static int service_start(svc_t *svc) if (len == 0) break; - if (svc->notify) { + if (svc->notify == SVC_NOTIFY_SYSTEMD || svc->notify == SVC_NOTIFY_S6) { char *ptr = strstr(arg, "%n"); if (ptr) { @@ -907,6 +908,19 @@ static void service_kill(svc_t *svc) print(2, NULL); } +/* Ensure we don't have any notify socket lingering */ +static void service_notify_stop(svc_t *svc) +{ + if (svc->notify != SVC_NOTIFY_SYSTEMD && svc->notify != SVC_NOTIFY_S6) + return; + + uev_io_stop(&svc->notify_watcher); + if (svc->notify_watcher.fd > 0) { + close(svc->notify_watcher.fd); + svc->notify_watcher.fd = 0; + } +} + /* * Clean up any lingering state from dead/killed services */ @@ -922,12 +936,7 @@ static void service_cleanup(svc_t *svc) logit(LOG_CRIT, "Failed removing service %s pidfile %s", svc_ident(svc, NULL, 0), fn); - /* Ensure we don't have any notify socket lingering */ - if (svc->notify && svc->notify_watcher.fd > 0) { - uev_io_stop(&svc->notify_watcher); - close(svc->notify_watcher.fd); - svc->notify_watcher.fd = 0; - } + service_notify_stop(svc); /* No longer running, update books. */ if (svc_is_tty(svc) && svc->pid > 1) @@ -1188,13 +1197,15 @@ static void parse_log(svc_t *svc, char *arg) } } -static int parse_notify(char *arg) +static svc_notify_t parse_notify(char *arg) { if (!strcmp(arg, "systemd")) - return 1; + return SVC_NOTIFY_SYSTEMD; if (!strcmp(arg, "s6")) - return 2; - return 0; /* unsupported/disabled */ + return SVC_NOTIFY_S6; + if (!strcmp(arg, "pid")) + return SVC_NOTIFY_PID; + return SVC_NOTIFY_NONE; /* unsupported/none */ } static void parse_env(svc_t *svc, char *env) @@ -1759,17 +1770,12 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) else svc->log.enabled = 0; } - if (notify) { - int type = parse_notify(notify); - if (type <= 0) - goto disable_notify; - svc->notify = type; - } else if (svc->notify) { - disable_notify: - /* XXX: close existing socket */ - svc->notify = 0; - } + if (notify) + svc->notify = parse_notify(notify); + else + svc->notify = readiness; + if (desc) strlcpy(svc->desc, desc, sizeof(svc->desc)); else if (type == SVC_TYPE_TTY) @@ -2373,11 +2379,7 @@ restart: char condstr[MAX_COND_LEN]; dbg("%s: stopped, cleaning up timers and conditions ...", svc_ident(svc, NULL, 0)); - if (svc->notify && svc->notify_watcher.fd > 0) { - uev_io_stop(&svc->notify_watcher); - close(svc->notify_watcher.fd); - svc->notify_watcher.fd = 0; - } + service_notify_stop(svc); service_timeout_cancel(svc); cond_clear(mkcond(svc, condstr, sizeof(condstr))); @@ -2686,7 +2688,7 @@ void service_notify_reconf(void) svc_t *svc, *iter = NULL; for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) { - if (!svc->notify) + if (svc->notify == SVC_NOTIFY_PID) continue; /* managed by pidfile plugin */ if (svc->state != SVC_RUNNING_STATE) @@ -2739,7 +2741,7 @@ void service_notify_cb(uev_t *w, void *arg, int events) service_ready(svc); /* s6 applications close their socket after notification */ - if (svc->notify == 2) { + if (svc->notify == SVC_NOTIFY_S6) { uev_io_stop(w); close(w->fd); w->fd = 0; diff --git a/src/svc.h b/src/svc.h index 5aaaadaa..f94a30e5 100644 --- a/src/svc.h +++ b/src/svc.h @@ -83,6 +83,14 @@ typedef enum { SVC_ONCRASH_SCRIPT, } svc_oncrash_action_t; +/* 0: none, 1: systemd, 2: s6 */ +typedef enum { + SVC_NOTIFY_NONE = 0, + SVC_NOTIFY_PID, + SVC_NOTIFY_SYSTEMD, + SVC_NOTIFY_S6, +} svc_notify_t; + #define MAX_ID_LEN 16 #define MAX_ARG_LEN 64 #define MAX_CMD_LEN 256 @@ -202,7 +210,7 @@ typedef struct svc { /* * Readiness notification socket: systemd, s6 */ - int notify; /* 0: none, 1: systemd, 2: s6 */ + svc_notify_t notify; uev_t notify_watcher; /* i/o watcher */ /* time at svc_del(), used by gc timer */ diff --git a/system/10-hotplug.conf.in b/system/10-hotplug.conf.in index fc4981c5..603a490f 100644 --- a/system/10-hotplug.conf.in +++ b/system/10-hotplug.conf.in @@ -18,8 +18,8 @@ # change the contents any way you like, it can even be empty. # Check for systemd-udevd and eudev, if we find both, we opt for the latter. -service nowarn [S12345789] cgroup.system name:udevd pid:udevd log /lib/systemd/systemd-udevd -- Device event daemon (udev) -service nowarn [S12345789] cgroup.system name:udevd pid:udevd log udevd -D -- Device event daemon (udev) +service nowarn [S12345789] cgroup.system name:udevd notify:none pid:udevd log /lib/systemd/systemd-udevd -- Device event daemon (udev) +service nowarn [S12345789] cgroup.system name:udevd notify:none pid:udevd log udevd -D -- Device event daemon (udev) # Wait for udevd to start, then trigger coldplug events and module loading. # The last 'settle' call waits for it to finalize processing all uevents. @@ -34,7 +34,7 @@ run nowarn if:udevd cgroup.init :5 [S] log udevadm settle -t 30 # (same as for plain mdev below) can be relied on as a # barrier for services that, e.g., need to probe for switchcore ports or PHYs # that require firmware loading before they show up. -service nowarn conflict:udevd,mdev cgroup.init if:!udevd \ +service nowarn conflict:udevd,mdev cgroup.init notify:none if:!udevd \ [S12345789] notify:s6 mdevd -O 4 -D %n -- Device event daemon (mdevd) run nowarn conflict:udevd,mdev cgroup.init name:coldplug \ [S] mdevd-coldplug -- Cold plugging system @@ -42,7 +42,7 @@ run nowarn conflict:udevd,mdev cgroup.init name:coldplug cgroup.system \ + cgroup.system notify:none \ /sbin/serv -n -p -i testserv -- Test serv daemon