diff --git a/doc/config.md b/doc/config.md index 8d61e4bd..d676da6d 100644 --- a/doc/config.md +++ b/doc/config.md @@ -164,14 +164,19 @@ everything is OK. task [S] /lib/console-setup/console-setup.sh service [S12345] env:-/etc/default/rsyslog rsyslogd -n $RSYSLOGD_ARGS -After runlevel S, Finit proceeds to runlevel 2. (This can be changed in -`/etc/finit.conf` using the `runlevel N` directive.) Before starting -the services in runlevel 2, Finit first stops everything that is not -allowed to run in 2, and then brings up networking. Networking is -expected to be available in all runlevels except: S, 1 (single user -level), 6, and 0. Networking is enabled either by the `network script` -directive, or if you have an `/etc/network/interfaces` file, Finit calls -`ifup -a` -- at the very least the loopback interface is brought up. +After runlevel S, Finit proceeds to runlevel 2. This can be changed in +`/etc/finit.conf` using the `runlevel N` directive, or by a script +running in runlevel S that calls, e.g., `initctl runlevel 9`. The +latter is useful if startup scripts detect problems outside of Finit's +control, e.g., critical services/devices missing or hardware problems. + +Before starting the services in runlevel 2, Finit first stops everything +that is not allowed to run in 2, and then brings up networking. +Networking is expected to be available in all runlevels except: S, 1 +(single user level), 6, and 0. Networking is enabled either by the +`network script` directive, or if you have an `/etc/network/interfaces` +file, Finit calls `ifup -a` -- at the very least the loopback interface +is brought up. > **Note:** when moving from runlevel S to 2, all run/task/services that > were constrained to runlevel S only are dropped from bookkeeping. So diff --git a/man/initctl.8 b/man/initctl.8 index 29909c92..1d6ab842 100644 --- a/man/initctl.8 +++ b/man/initctl.8 @@ -240,6 +240,11 @@ Show top-like listing based on cgroups. List installed plugins. .It Nm Ar runlevel Op Ar 0-9 Show or set runlevel: 0 halt, 6 reboot. +.Pp +If called at boot (runlevel S) to set the runlevel, Finit only schedules +the change, effectively overriding the configured runlevel from +.Pa /etc/finit.conf . +Useful to trigger a fail-safe mode, or similar. .It Nm Ar reboot Reboot system, default if .Cm reboot diff --git a/src/api.c b/src/api.c index 7bcc8ffc..6c6a7af6 100644 --- a/src/api.c +++ b/src/api.c @@ -367,7 +367,6 @@ static void api_cb(uev_t *w, void *arg, int events) } switch (rq.cmd) { - case INIT_CMD_RUNLVL: case INIT_CMD_RELOAD: case INIT_CMD_START_SVC: case INIT_CMD_RESTART_SVC: @@ -378,7 +377,7 @@ static void api_cb(uev_t *w, void *arg, int events) case INIT_CMD_POWEROFF: case INIT_CMD_SUSPEND: if (IS_RESERVED_RUNLEVEL(runlevel)) { - warnx("Unsupported command in runlevel S and 6."); + warnx("Unsupported command in runlevel S and 6/0."); goto leave; } default: @@ -387,6 +386,14 @@ static void api_cb(uev_t *w, void *arg, int events) switch (rq.cmd) { case INIT_CMD_RUNLVL: + /* Allow changing cfglevel in runlevel S */ + if (IS_RESERVED_RUNLEVEL(runlevel)) { + if (runlevel != INIT_LEVEL) { + warnx("Cannot abort runlevel 6/0."); + break; + } + } + switch (rq.runlevel) { case 's': case 'S': @@ -400,7 +407,12 @@ static void api_cb(uev_t *w, void *arg, int events) halt = SHUT_OFF; if (lvl == 6) halt = SHUT_REBOOT; - service_runlevel(lvl); + + /* User requested change in next runlevel */ + if (runlevel == INIT_LEVEL) + cfglevel = lvl; + else + service_runlevel(lvl); break; default: