diff --git a/doc/conditions.md b/doc/conditions.md index e4dcd9ac..207b8506 100644 --- a/doc/conditions.md +++ b/doc/conditions.md @@ -27,6 +27,16 @@ specified separated by comma. Multiple conditions are logically AND'ed during evaluation, i.e. all conditions must be satisfied in order for a service to run. +A special syntax, using a leading `!` in run/task/service conditions, +denote if a: + + - service does not support `SIGHUP` + - run/task should not block runlevel changes (i.e., bootstrap) + +Finit guarantees by default that all run/tasks run (at least) once +per runlevel. For most tasks this is a good default, for example +checking SSH host keys or loading keymap. However, for conditions +that are unlikely to happen it is not. (See example below.) ### Example @@ -41,6 +51,19 @@ being created, i.e., the service's default readiness notification. asserted. I.e., if the Zebra process above stops or restarts, netd will also stop or restart. +Another example is `dropbear`, it does not support `SIGHUP`, but we can +also see optional sourcing of arguments from an environment file: + + service [2345789] env:-/etc/default/dropbear dropbear -F -R $DROPBEAR_ARGS -- Dropbear SSH daemon + +Finally, the weird "block runlevel changes" example. Here we see what +happens when Finit receives `SIGPWR`, sent from a power daemon like +[powstatd(8)][]. A condition is asserted and a user can set up their +own task to act on it. We do not want this task to block Finit from +moving to the next runlevel after bootstrap, so we set ``: + + task [S0123456789] name:pwrfail initctl poweroff -- Power failure, shutting down + Triggering ---------- @@ -260,3 +283,5 @@ Therefore, any plugin that supplies Finit with conditions must ensure that their state is updated after each reconfiguration. This can be done by binding to the `HOOK_SVC_RECONF` hook. For an example of how to do this, see `plugins/pidfile.c`. + +[powstatd(8)]: https://manpages.ubuntu.com/manpages/trusty/en/man8/powstatd.8.html diff --git a/src/conf.c b/src/conf.c index bd03f9df..61a538c3 100644 --- a/src/conf.c +++ b/src/conf.c @@ -656,11 +656,22 @@ void conf_parse_cond(svc_t *svc, char *cond) return; } - /* First character must be '!' if SIGHUP is not supported. */ + /* + * First character must be '!' if: + * - service: SIGHUP is not supported + * - run/task: Do not block bootstrap + */ ptr = cond; if (ptr[i] == '!') { - svc->sighup = 0; ptr++; + + if (svc_is_runtask(svc)) { + /* see service_runtask_clean() */ + svc->sighup = 1; + svc->once = 1; + } else { + svc->sighup = 0; + } } while (ptr[i] != '>' && ptr[i] != 0) diff --git a/src/service.c b/src/service.c index 7b758c9b..a905e0be 100644 --- a/src/service.c +++ b/src/service.c @@ -1414,7 +1414,11 @@ static void parse_cmdline_args(svc_t *svc, char *cmd, char **args) * before they are started. Or restarted, or even SIGHUP'ed, when the * gateway changes or interfaces come and go. The special case when a * service is declared with means it does not support SIGHUP but - * must be STOP/START'ed at system reconfiguration. + * must be STOP/START'ed at system reconfiguration. For run/task a + * means Finit can relax its promise to run at least once per runlevel. + * I.e., for run/task conditions that would otherwise block bootstrap: + * + * task [S0123456789] name:pwrfail initctl poweroff -- Power failure, shutting down * * Conditions can for example be: pid/NAME:ID for process dependencies, * net//up or net//exists. The condition handling is @@ -2500,7 +2504,7 @@ restart: case COND_ON: if (svc_is_changed(svc)) { - if (svc_nohup(svc)) + if (svc_nohup(svc) || !svc_is_daemon(svc)) service_stop(svc); else { /* @@ -2601,7 +2605,12 @@ void service_runtask_clean(void) if (!svc_is_runtask(svc)) continue; - svc->once = 0; + /* run/task declared with */ + if (svc->sighup) + svc->once = 1; + else + svc->once = 0; + if (svc->state == SVC_DONE_STATE) svc_set_state(svc, SVC_HALTED_STATE); }