Fix #352: separate runlevel S from runlevel 0

Due to an old design decision runlevel S was encoded internally as '0',
meaning it was the same as halt/poweroff.  If you want to run scripts at
system shutdown this was less then ideal since it meant your scripts
also ran at bootstrap.

This change is quite invasive.  It introduces INIT_LEVEL (10) as the
value for runlevel S, meaning all code that parses and/or evaluates
anything for runlevel 0/S was affected and had to be reworked.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg
2023-04-22 15:11:27 +02:00
parent 80191f2fd5
commit e00fda5dc3
12 changed files with 67 additions and 47 deletions
+16 -16
View File
@@ -244,7 +244,7 @@ networking here. The configured `runlevel NUM` from `/etc/finit.conf`
is what Finit changes to after bootstrap, unless 'single' (or 'S') is is what Finit changes to after bootstrap, unless 'single' (or 'S') is
given on the kernel cmdline, in which case runlevel 1 is started. given on the kernel cmdline, in which case runlevel 1 is started.
All services in runlevel S(0) are started first, followed by the desired All services in runlevel S) are started first, followed by the desired
run-time runlevel. Run tasks in runlevel S can be started in sequence run-time runlevel. Run tasks in runlevel S can be started in sequence
by using `run [S] cmd`. Changing runlevels at runtime is done like any by using `run [S] cmd`. Changing runlevels at runtime is done like any
other init, e.g. <kbd>init 4</kbd>, but also using the more advanced other init, e.g. <kbd>init 4</kbd>, but also using the more advanced
@@ -585,24 +585,24 @@ scripting and documentation:
``` ```
alpine:~# initctl -p alpine:~# initctl -p
PID IDENT STATUS RUNLEVELS DESCRIPTION PID IDENT STATUS RUNLEVELS DESCRIPTION
====================================================================== ======================================================================
1506 acpid running [--2345----] ACPI daemon 1506 acpid running [---2345----] ACPI daemon
1509 crond running [--2345----] Cron daemon 1509 crond running [---2345----] Cron daemon
1489 dropbear running [--2345----] Dropbear SSH daemon 1489 dropbear running [---2345----] Dropbear SSH daemon
1511 klogd running [S12345----] Kernel log daemon 1511 klogd running [S-12345----] Kernel log daemon
1512 ntpd running [--2345----] NTP daemon 1512 ntpd running [---2345----] NTP daemon
1473 syslogd running [S12345----] Syslog daemon 1473 syslogd running [S-12345----] Syslog daemon
alpine:~# initctl -pv alpine:~# initctl -pv
PID IDENT STATUS RUNLEVELS COMMAND PID IDENT STATUS RUNLEVELS COMMAND
====================================================================== ======================================================================
1506 acpid running [--2345----] acpid -f 1506 acpid running [---2345----] acpid -f
1509 crond running [--2345----] crond -f -S $CRON_OPTS 1509 crond running [---2345----] crond -f -S $CRON_OPTS
1489 dropbear running [--2345----] dropbear -R -F $DROPBEAR_OPTS 1489 dropbear running [---2345----] dropbear -R -F $DROPBEAR_OPTS
1511 klogd running [S12345----] klogd -n $KLOGD_OPTS 1511 klogd running [S-12345----] klogd -n $KLOGD_OPTS
1512 ntpd running [--2345----] ntpd -n $NTPD_OPTS 1512 ntpd running [---2345----] ntpd -n $NTPD_OPTS
1473 syslogd running [S12345----] syslogd -n 1473 syslogd running [S-12345----] syslogd -n
``` ```
The environment variables to each of the services above are read from, The environment variables to each of the services above are read from,
@@ -627,7 +627,7 @@ Condition(s):
User : root User : root
Group : root Group : root
Uptime : 2 hour 46 min 56 sec Uptime : 2 hour 46 min 56 sec
Runlevels : [--2345----] Runlevels : [---2345----]
Memory : 1.2M Memory : 1.2M
CGroup : /system/dropbear cpu 0 [100, max] mem [--.--, max] CGroup : /system/dropbear cpu 0 [100, max] mem [--.--, max]
|- 1485 dropbear -R -F |- 1485 dropbear -R -F
+1 -1
View File
@@ -375,7 +375,7 @@ static void api_cb(uev_t *w, void *arg, int events)
case INIT_CMD_HALT: case INIT_CMD_HALT:
case INIT_CMD_POWEROFF: case INIT_CMD_POWEROFF:
case INIT_CMD_SUSPEND: case INIT_CMD_SUSPEND:
if (runlevel == 0 || runlevel == 6) { if (IS_RESERVED_RUNLEVEL(runlevel)) {
warnx("Unsupported command in runlevel S and 6."); warnx("Unsupported command in runlevel S and 6.");
goto leave; goto leave;
} }
+7 -6
View File
@@ -48,7 +48,7 @@
#include "helpers.h" #include "helpers.h"
#include "util.h" #include "util.h"
#define BOOTSTRAP (runlevel == 0) #define BOOTSTRAP (runlevel == INIT_LEVEL)
int logfile_size_max = 200000; /* 200 kB */ int logfile_size_max = 200000; /* 200 kB */
int logfile_count_max = 5; int logfile_count_max = 5;
@@ -475,7 +475,7 @@ static void kmod_load(char *mod)
char module[64] = { 0 }; char module[64] = { 0 };
char cmd[CMD_SIZE]; char cmd[CMD_SIZE];
if (runlevel != 0) if (runlevel != INIT_LEVEL)
return; return;
/* Strip args for progress below and kmod_exists() */ /* Strip args for progress below and kmod_exists() */
@@ -508,15 +508,16 @@ int conf_parse_runlevels(char *runlevels)
break; break;
if ('!' == lvl) { if ('!' == lvl) {
not = 1; not = 1;
bitmask = 0x3FE; bitmask = 0x7FE;
continue; continue;
} }
if ('s' == lvl || 'S' == lvl) if ('s' == lvl || 'S' == lvl)
lvl = '0'; level = INIT_LEVEL;
else
level = lvl - '0';
level = lvl - '0'; if (level > INIT_LEVEL || level < 0)
if (level > 9 || level < 0)
continue; continue;
if (not) if (not)
+1 -1
View File
@@ -60,7 +60,7 @@
#include "utmp-api.h" #include "utmp-api.h"
#include "schedule.h" #include "schedule.h"
int runlevel = 0; /* Bootstrap 'S' */ int runlevel = INIT_LEVEL; /* Bootstrap 'S' */
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */ int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
int cmdlevel = 0; /* runlevel override from cmdline */ int cmdlevel = 0; /* runlevel override from cmdline */
int prevlevel = -1; int prevlevel = -1;
+2 -1
View File
@@ -63,10 +63,11 @@
#define LINE_SIZE 1024 #define LINE_SIZE 1024
#define BUF_SIZE 4096 #define BUF_SIZE 4096
/* We extend the INIT_CMD_ range for the new initctl tool. */
#define INIT_SOCKET _PATH_VARRUN "finit/socket" #define INIT_SOCKET _PATH_VARRUN "finit/socket"
#define INIT_MAGIC 0x03091969 #define INIT_MAGIC 0x03091969
#define INIT_LEVEL 10
/* We extend the INIT_CMD_ range for the new initctl tool. */
#define INIT_CMD_START 0 #define INIT_CMD_START 0
#define INIT_CMD_RUNLVL 1 #define INIT_CMD_RUNLVL 1
#define INIT_CMD_POWERFAIL 2 #define INIT_CMD_POWERFAIL 2
+24 -10
View File
@@ -761,17 +761,18 @@ static int plugins_list(char *arg)
char *runlevel_string(int currlevel, int levels) char *runlevel_string(int currlevel, int levels)
{ {
static char lvl[21]; static char lvl[21];
int i, pos = 1; int i = INIT_LEVEL;
int pos = 1;
memset(lvl, 0, sizeof(lvl)); memset(lvl, 0, sizeof(lvl));
lvl[0] = '['; lvl[0] = '[';
for (i = 0; i < 10; i++) { do {
if (ISSET(levels, i)) { if (ISSET(levels, i)) {
if (!plain && currlevel == i) if (!plain && currlevel == i)
pos = strlcat(lvl, "\e[1m", sizeof(lvl)); pos = strlcat(lvl, "\e[1m", sizeof(lvl));
if (i == 0) if (i == INIT_LEVEL)
lvl[pos++] = 'S'; lvl[pos++] = 'S';
else else
lvl[pos++] = '0' + i; lvl[pos++] = '0' + i;
@@ -781,7 +782,14 @@ char *runlevel_string(int currlevel, int levels)
} else { } else {
lvl[pos++] = '-'; lvl[pos++] = '-';
} }
}
/* XXX: ugly hack to get order right: S0123456789 */
if (i == INIT_LEVEL)
i = 0;
else
i++;
} while (i < INIT_LEVEL);
lvl[pos++] = ']'; lvl[pos++] = ']';
lvl[pos] = 0; lvl[pos] = 0;
@@ -792,18 +800,24 @@ char *runlevel_string(int currlevel, int levels)
char *runlevel_arr(int levels) char *runlevel_arr(int levels)
{ {
static char lvl[42]; static char lvl[42];
int i = INIT_LEVEL;
int p = 2, s = 0; int p = 2, s = 0;
strlcpy(lvl, "[ ", sizeof(lvl)); strlcpy(lvl, "[ ", sizeof(lvl));
for (int i = 0; i < 10; i++) { do {
if (ISSET(levels, i)) { if (ISSET(levels, i)) {
if (i == 0) if (i == INIT_LEVEL)
p += snprintf(&lvl[p], sizeof(lvl) - p, "\"S\""); p += snprintf(&lvl[p], sizeof(lvl) - p, "\"S\"");
else else
p += snprintf(&lvl[p], sizeof(lvl) - p, "%s%c", s ? ", " : "", '0' + i); p += snprintf(&lvl[p], sizeof(lvl) - p, "%s%c", s ? ", " : "", '0' + i);
s++; s++;
} }
} /* XXX: ugly hack to get order right: S0123456789 */
if (i == INIT_LEVEL)
i = 0;
else
i++;
} while (i < INIT_LEVEL);
strlcat(lvl, " ]", sizeof(lvl)); strlcat(lvl, " ]", sizeof(lvl));
return lvl; return lvl;
@@ -1162,7 +1176,7 @@ static int show_status(char *arg)
if (heading) { if (heading) {
char title[80]; char title[80];
snprintf(title, sizeof(title), "%-*s %-*s %-8s %-12s ", snprintf(title, sizeof(title), "%-*s %-*s %-8s %-13s ",
pw, "PID", iw, "IDENT", "STATUS", "RUNLEVELS"); pw, "PID", iw, "IDENT", "STATUS", "RUNLEVELS");
if (!verbose) if (!verbose)
strlcat(title, "DESCRIPTION", sizeof(title)); strlcat(title, "DESCRIPTION", sizeof(title));
@@ -1184,9 +1198,9 @@ static int show_status(char *arg)
lvls = runlevel_string(runlevel, svc->runlevels); lvls = runlevel_string(runlevel, svc->runlevels);
if (strchr(lvls, '\e')) if (strchr(lvls, '\e'))
printf("%-20.20s ", lvls); printf("%-21.21s ", lvls);
else else
printf("%-12.12s ", lvls); printf("%-13.13s ", lvls);
if (!verbose) if (!verbose)
puts(svc->desc); puts(svc->desc);
+2
View File
@@ -32,6 +32,8 @@
#define MATCH_CMD(l, c, x) \ #define MATCH_CMD(l, c, x) \
(!strncasecmp(l, c, strlen(c)) && (x = (l) + strlen(c))) (!strncasecmp(l, c, strlen(c)) && (x = (l) + strlen(c)))
#define IS_RESERVED_RUNLEVEL(l) (l == 0 || l == 6 || l == INIT_LEVEL)
extern char *finit_conf; extern char *finit_conf;
extern char *finit_rcsd; extern char *finit_rcsd;
extern svc_t *wdog; extern svc_t *wdog;
+4 -4
View File
@@ -1051,7 +1051,7 @@ static int service_restart(svc_t *svc)
} }
/* Skip progress if desc disabled or bootstrap task */ /* Skip progress if desc disabled or bootstrap task */
if (!svc->desc[0] || svc_in_runlevel(svc, 0)) if (!svc->desc[0] || svc_in_runlevel(svc, INIT_LEVEL))
do_progress = 0; do_progress = 0;
if (do_progress) if (do_progress)
@@ -1106,13 +1106,13 @@ void service_reload_dynamic(void)
*/ */
void service_runlevel(int newlevel) void service_runlevel(int newlevel)
{ {
if (!rescue && runlevel <= 1 && newlevel > 1) if (!rescue && (runlevel == 1 || runlevel == INIT_LEVEL) && !IS_RESERVED_RUNLEVEL(newlevel))
networking(1); networking(1);
sm_set_runlevel(&sm, newlevel); sm_set_runlevel(&sm, newlevel);
sm_step(&sm); sm_step(&sm);
if (!rescue && (runlevel <= 1 || runlevel == 6)) if (!rescue && IS_RESERVED_RUNLEVEL(runlevel))
networking(0); networking(0);
} }
@@ -1538,7 +1538,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
id = ""; id = "";
levels = conf_parse_runlevels(runlevels); levels = conf_parse_runlevels(runlevels);
if (runlevel > 0 && !ISOTHER(levels, 0)) { if (runlevel != INIT_LEVEL && !ISOTHER(levels, 0)) {
dbg("Skipping %s%s%s, bootstrap is completed.", dbg("Skipping %s%s%s, bootstrap is completed.",
name, id[0] ? ":" : "", id[0] ? id : ""); name, id[0] ? ":" : "", id[0] ? id : "");
return 0; return 0;
+4 -4
View File
@@ -429,7 +429,7 @@ static void sighup_cb(uev_t *w, void *arg, int events)
return; return;
} }
if (runlevel == 0 || runlevel == 6) { if (IS_RESERVED_RUNLEVEL(runlevel)) {
warnx("SIGHUP ignored in runlevel S and 6."); warnx("SIGHUP ignored in runlevel S and 6.");
return; return;
} }
@@ -485,7 +485,7 @@ static void sigusr1_cb(uev_t *w, void *arg, int events)
return; return;
} }
if (runlevel == 0 || runlevel == 6) { if (IS_RESERVED_RUNLEVEL(runlevel)) {
warnx("SIGUSR1 ignored in runlevel S and 6."); warnx("SIGUSR1 ignored in runlevel S and 6.");
return; return;
} }
@@ -506,7 +506,7 @@ static void sigusr2_cb(uev_t *w, void *arg, int events)
return; return;
} }
if (runlevel == 0 || runlevel == 6) { if (IS_RESERVED_RUNLEVEL(runlevel)) {
warnx("SIGUSR2 ignored in runlevel S and 6."); warnx("SIGUSR2 ignored in runlevel S and 6.");
return; return;
} }
@@ -526,7 +526,7 @@ static void sigterm_cb(uev_t *w, void *arg, int events)
return; return;
} }
if (runlevel == 0 || runlevel == 6) { if (IS_RESERVED_RUNLEVEL(runlevel)) {
warnx("SIGTERM ignored in runlevel S and 6."); warnx("SIGTERM ignored in runlevel S and 6.");
return; return;
} }
+2 -2
View File
@@ -86,10 +86,10 @@ static char *sm_status(sm_state_t state)
*/ */
static void nologin(void) static void nologin(void)
{ {
if (runlevel == 1 || runlevel == 0 || runlevel == 6) if (runlevel == 1 || IS_RESERVED_RUNLEVEL(runlevel))
touch(FINIT_NOLOGIN_PATH); touch(FINIT_NOLOGIN_PATH);
if (prevlevel == 1 || prevlevel == 0 || prevlevel == 6) if (prevlevel == 1 || IS_RESERVED_RUNLEVEL(prevlevel))
erase(FINIT_NOLOGIN_PATH); erase(FINIT_NOLOGIN_PATH);
} }
+1 -1
View File
@@ -594,7 +594,7 @@ void svc_clean_dynamic(void (*cb)(svc_t *))
*/ */
int svc_clean_bootstrap(svc_t *svc) int svc_clean_bootstrap(svc_t *svc)
{ {
if (!ISOTHER(svc->runlevels, 0)) { if (!ISOTHER(svc->runlevels, INIT_LEVEL)) {
svc->pid = 0; svc->pid = 0;
svc_del(svc); svc_del(svc);
return 1; return 1;
+3 -1
View File
@@ -32,6 +32,7 @@
# include <lite/lite.h> # include <lite/lite.h>
#endif #endif
#include "finit.h"
#include "helpers.h" #include "helpers.h"
#include "util.h" #include "util.h"
#include "utmp-api.h" #include "utmp-api.h"
@@ -174,7 +175,8 @@ int utmp_set_dead(int pid)
static int encode(int lvl) static int encode(int lvl)
{ {
if (!lvl) return 0; if (lvl == INIT_LEVEL)
return 0;
return lvl + '0'; return lvl + '0';
} }