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
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
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
@@ -585,24 +585,24 @@ scripting and documentation:
```
alpine:~# initctl -p
PID IDENT STATUS RUNLEVELS DESCRIPTION
PID IDENT STATUS RUNLEVELS DESCRIPTION
======================================================================
1506 acpid running [--2345----] ACPI daemon
1509 crond running [--2345----] Cron daemon
1489 dropbear running [--2345----] Dropbear SSH daemon
1511 klogd running [S12345----] Kernel log daemon
1512 ntpd running [--2345----] NTP daemon
1473 syslogd running [S12345----] Syslog daemon
1506 acpid running [---2345----] ACPI daemon
1509 crond running [---2345----] Cron daemon
1489 dropbear running [---2345----] Dropbear SSH daemon
1511 klogd running [S-12345----] Kernel log daemon
1512 ntpd running [---2345----] NTP daemon
1473 syslogd running [S-12345----] Syslog daemon
alpine:~# initctl -pv
PID IDENT STATUS RUNLEVELS COMMAND
PID IDENT STATUS RUNLEVELS COMMAND
======================================================================
1506 acpid running [--2345----] acpid -f
1509 crond running [--2345----] crond -f -S $CRON_OPTS
1489 dropbear running [--2345----] dropbear -R -F $DROPBEAR_OPTS
1511 klogd running [S12345----] klogd -n $KLOGD_OPTS
1512 ntpd running [--2345----] ntpd -n $NTPD_OPTS
1473 syslogd running [S12345----] syslogd -n
1506 acpid running [---2345----] acpid -f
1509 crond running [---2345----] crond -f -S $CRON_OPTS
1489 dropbear running [---2345----] dropbear -R -F $DROPBEAR_OPTS
1511 klogd running [S-12345----] klogd -n $KLOGD_OPTS
1512 ntpd running [---2345----] ntpd -n $NTPD_OPTS
1473 syslogd running [S-12345----] syslogd -n
```
The environment variables to each of the services above are read from,
@@ -627,7 +627,7 @@ Condition(s):
User : root
Group : root
Uptime : 2 hour 46 min 56 sec
Runlevels : [--2345----]
Runlevels : [---2345----]
Memory : 1.2M
CGroup : /system/dropbear cpu 0 [100, max] mem [--.--, max]
|- 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_POWEROFF:
case INIT_CMD_SUSPEND:
if (runlevel == 0 || runlevel == 6) {
if (IS_RESERVED_RUNLEVEL(runlevel)) {
warnx("Unsupported command in runlevel S and 6.");
goto leave;
}
+7 -6
View File
@@ -48,7 +48,7 @@
#include "helpers.h"
#include "util.h"
#define BOOTSTRAP (runlevel == 0)
#define BOOTSTRAP (runlevel == INIT_LEVEL)
int logfile_size_max = 200000; /* 200 kB */
int logfile_count_max = 5;
@@ -475,7 +475,7 @@ static void kmod_load(char *mod)
char module[64] = { 0 };
char cmd[CMD_SIZE];
if (runlevel != 0)
if (runlevel != INIT_LEVEL)
return;
/* Strip args for progress below and kmod_exists() */
@@ -508,15 +508,16 @@ int conf_parse_runlevels(char *runlevels)
break;
if ('!' == lvl) {
not = 1;
bitmask = 0x3FE;
bitmask = 0x7FE;
continue;
}
if ('s' == lvl || 'S' == lvl)
lvl = '0';
level = INIT_LEVEL;
else
level = lvl - '0';
level = lvl - '0';
if (level > 9 || level < 0)
if (level > INIT_LEVEL || level < 0)
continue;
if (not)
+1 -1
View File
@@ -60,7 +60,7 @@
#include "utmp-api.h"
#include "schedule.h"
int runlevel = 0; /* Bootstrap 'S' */
int runlevel = INIT_LEVEL; /* Bootstrap 'S' */
int cfglevel = RUNLEVEL; /* Fallback if no configured runlevel */
int cmdlevel = 0; /* runlevel override from cmdline */
int prevlevel = -1;
+2 -1
View File
@@ -63,10 +63,11 @@
#define LINE_SIZE 1024
#define BUF_SIZE 4096
/* We extend the INIT_CMD_ range for the new initctl tool. */
#define INIT_SOCKET _PATH_VARRUN "finit/socket"
#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_RUNLVL 1
#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)
{
static char lvl[21];
int i, pos = 1;
int i = INIT_LEVEL;
int pos = 1;
memset(lvl, 0, sizeof(lvl));
lvl[0] = '[';
for (i = 0; i < 10; i++) {
do {
if (ISSET(levels, i)) {
if (!plain && currlevel == i)
pos = strlcat(lvl, "\e[1m", sizeof(lvl));
if (i == 0)
if (i == INIT_LEVEL)
lvl[pos++] = 'S';
else
lvl[pos++] = '0' + i;
@@ -781,7 +782,14 @@ char *runlevel_string(int currlevel, int levels)
} else {
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] = 0;
@@ -792,18 +800,24 @@ char *runlevel_string(int currlevel, int levels)
char *runlevel_arr(int levels)
{
static char lvl[42];
int i = INIT_LEVEL;
int p = 2, s = 0;
strlcpy(lvl, "[ ", sizeof(lvl));
for (int i = 0; i < 10; i++) {
do {
if (ISSET(levels, i)) {
if (i == 0)
if (i == INIT_LEVEL)
p += snprintf(&lvl[p], sizeof(lvl) - p, "\"S\"");
else
p += snprintf(&lvl[p], sizeof(lvl) - p, "%s%c", s ? ", " : "", '0' + i);
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));
return lvl;
@@ -1162,7 +1176,7 @@ static int show_status(char *arg)
if (heading) {
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");
if (!verbose)
strlcat(title, "DESCRIPTION", sizeof(title));
@@ -1184,9 +1198,9 @@ static int show_status(char *arg)
lvls = runlevel_string(runlevel, svc->runlevels);
if (strchr(lvls, '\e'))
printf("%-20.20s ", lvls);
printf("%-21.21s ", lvls);
else
printf("%-12.12s ", lvls);
printf("%-13.13s ", lvls);
if (!verbose)
puts(svc->desc);
+2
View File
@@ -32,6 +32,8 @@
#define MATCH_CMD(l, c, x) \
(!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_rcsd;
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 */
if (!svc->desc[0] || svc_in_runlevel(svc, 0))
if (!svc->desc[0] || svc_in_runlevel(svc, INIT_LEVEL))
do_progress = 0;
if (do_progress)
@@ -1106,13 +1106,13 @@ void service_reload_dynamic(void)
*/
void service_runlevel(int newlevel)
{
if (!rescue && runlevel <= 1 && newlevel > 1)
if (!rescue && (runlevel == 1 || runlevel == INIT_LEVEL) && !IS_RESERVED_RUNLEVEL(newlevel))
networking(1);
sm_set_runlevel(&sm, newlevel);
sm_step(&sm);
if (!rescue && (runlevel <= 1 || runlevel == 6))
if (!rescue && IS_RESERVED_RUNLEVEL(runlevel))
networking(0);
}
@@ -1538,7 +1538,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
id = "";
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.",
name, id[0] ? ":" : "", id[0] ? id : "");
return 0;
+4 -4
View File
@@ -429,7 +429,7 @@ static void sighup_cb(uev_t *w, void *arg, int events)
return;
}
if (runlevel == 0 || runlevel == 6) {
if (IS_RESERVED_RUNLEVEL(runlevel)) {
warnx("SIGHUP ignored in runlevel S and 6.");
return;
}
@@ -485,7 +485,7 @@ static void sigusr1_cb(uev_t *w, void *arg, int events)
return;
}
if (runlevel == 0 || runlevel == 6) {
if (IS_RESERVED_RUNLEVEL(runlevel)) {
warnx("SIGUSR1 ignored in runlevel S and 6.");
return;
}
@@ -506,7 +506,7 @@ static void sigusr2_cb(uev_t *w, void *arg, int events)
return;
}
if (runlevel == 0 || runlevel == 6) {
if (IS_RESERVED_RUNLEVEL(runlevel)) {
warnx("SIGUSR2 ignored in runlevel S and 6.");
return;
}
@@ -526,7 +526,7 @@ static void sigterm_cb(uev_t *w, void *arg, int events)
return;
}
if (runlevel == 0 || runlevel == 6) {
if (IS_RESERVED_RUNLEVEL(runlevel)) {
warnx("SIGTERM ignored in runlevel S and 6.");
return;
}
+2 -2
View File
@@ -86,10 +86,10 @@ static char *sm_status(sm_state_t state)
*/
static void nologin(void)
{
if (runlevel == 1 || runlevel == 0 || runlevel == 6)
if (runlevel == 1 || IS_RESERVED_RUNLEVEL(runlevel))
touch(FINIT_NOLOGIN_PATH);
if (prevlevel == 1 || prevlevel == 0 || prevlevel == 6)
if (prevlevel == 1 || IS_RESERVED_RUNLEVEL(prevlevel))
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)
{
if (!ISOTHER(svc->runlevels, 0)) {
if (!ISOTHER(svc->runlevels, INIT_LEVEL)) {
svc->pid = 0;
svc_del(svc);
return 1;
+3 -1
View File
@@ -32,6 +32,7 @@
# include <lite/lite.h>
#endif
#include "finit.h"
#include "helpers.h"
#include "util.h"
#include "utmp-api.h"
@@ -174,7 +175,8 @@ int utmp_set_dead(int pid)
static int encode(int lvl)
{
if (!lvl) return 0;
if (lvl == INIT_LEVEL)
return 0;
return lvl + '0';
}