Fix #369: allow runlevel change using initctl during bootstrap

This change opens up the runlevel change API from bootstrap.  The twist
is that the change is only queued, i.e., the call `initctl runlevel 9`
during bootstrap only changes the configured runlevel to go to after
bootstrap has completed.

Effectively, this change allows overriding the `runlevel` directive in
/etc/finit.conf without having to change the file.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg committed 2023-10-03 15:11:33 +02:00
1 parent 338521a748
commit 2e73563eea
3 files changed
+33 -11

No files matched your search

+13 -8
View File
@@ -164,14 +164,19 @@ everything is OK.
task [S] /lib/console-setup/console-setup.sh task [S] /lib/console-setup/console-setup.sh
service [S12345] env:-/etc/default/rsyslog rsyslogd -n $RSYSLOGD_ARGS service [S12345] env:-/etc/default/rsyslog rsyslogd -n $RSYSLOGD_ARGS
After runlevel S, Finit proceeds to runlevel 2. (This can be changed in After runlevel S, Finit proceeds to runlevel 2. This can be changed in
`/etc/finit.conf` using the `runlevel N` directive.) Before starting `/etc/finit.conf` using the `runlevel N` directive, or by a script
the services in runlevel 2, Finit first stops everything that is not running in runlevel S that calls, e.g., `initctl runlevel 9`. The
allowed to run in 2, and then brings up networking. Networking is latter is useful if startup scripts detect problems outside of Finit's
expected to be available in all runlevels except: S, 1 (single user control, e.g., critical services/devices missing or hardware problems.
level), 6, and 0. Networking is enabled either by the `network script`
directive, or if you have an `/etc/network/interfaces` file, Finit calls Before starting the services in runlevel 2, Finit first stops everything
`ifup -a` -- at the very least the loopback interface is brought up. 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 > **Note:** when moving from runlevel S to 2, all run/task/services that
> were constrained to runlevel S only are dropped from bookkeeping. So > were constrained to runlevel S only are dropped from bookkeeping. So
+5
View File
@@ -240,6 +240,11 @@ Show top-like listing based on cgroups.
List installed plugins. List installed plugins.
.It Nm Ar runlevel Op Ar 0-9 .It Nm Ar runlevel Op Ar 0-9
Show or set runlevel: 0 halt, 6 reboot. 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 .It Nm Ar reboot
Reboot system, default if Reboot system, default if
.Cm reboot .Cm reboot
+15 -3
View File
@@ -367,7 +367,6 @@ static void api_cb(uev_t *w, void *arg, int events)
} }
switch (rq.cmd) { switch (rq.cmd) {
case INIT_CMD_RUNLVL:
case INIT_CMD_RELOAD: case INIT_CMD_RELOAD:
case INIT_CMD_START_SVC: case INIT_CMD_START_SVC:
case INIT_CMD_RESTART_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_POWEROFF:
case INIT_CMD_SUSPEND: case INIT_CMD_SUSPEND:
if (IS_RESERVED_RUNLEVEL(runlevel)) { if (IS_RESERVED_RUNLEVEL(runlevel)) {
warnx("Unsupported command in runlevel S and 6."); warnx("Unsupported command in runlevel S and 6/0.");
goto leave; goto leave;
} }
default: default:
@@ -387,6 +386,14 @@ static void api_cb(uev_t *w, void *arg, int events)
switch (rq.cmd) { switch (rq.cmd) {
case INIT_CMD_RUNLVL: 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) { switch (rq.runlevel) {
case 's': case 's':
case 'S': case 'S':
@@ -400,7 +407,12 @@ static void api_cb(uev_t *w, void *arg, int events)
halt = SHUT_OFF; halt = SHUT_OFF;
if (lvl == 6) if (lvl == 6)
halt = SHUT_REBOOT; halt = SHUT_REBOOT;
service_runlevel(lvl);
/* User requested change in next runlevel */
if (runlevel == INIT_LEVEL)
cfglevel = lvl;
else
service_runlevel(lvl);
break; break;
default: default: