From f7d6d269c74cf1084aec51b52dfaf4c06609e3f9 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sun, 18 Sep 2016 11:50:07 +0200 Subject: [PATCH] Change to runlevel 0/6 on reboot/halt/poweroff This patch fixes a long-standing issue with how Finit handles shutdown, reboot and poweroff -- and even runlevel changes to runlevel 0 and 6. Prior to this patch sig.c:do_shutdown() was called immediately on any of the above events, disregarding any services that a user might have wanted to run as part of the shutdown/reboot. With this change the handling is unified in all frontends to instead do a runlevel change followed by the do_shutdown() action. Signed-off-by: Joachim Nilsson --- TODO.md | 2 -- api.c | 30 ++++++++++++++---------------- plugins/initctl.c | 31 ++++++++++--------------------- sig.c | 19 +++++++++++++++---- sig.h | 2 ++ sm.c | 15 ++++++++------- 6 files changed, 49 insertions(+), 50 deletions(-) diff --git a/TODO.md b/TODO.md index 6239f364..ace43d7c 100644 --- a/TODO.md +++ b/TODO.md @@ -20,8 +20,6 @@ General * Add halt/poweroff/shutdown symlinks to finit and convert reboot, but only install symlinks if these tools don't already exist. -* Step state machine at shutdown instead of killing, same as shifting to - runlevel 0 or 6, then call external (newly installed?) tool to reboot. * Add support for timed shutdown in Finit, including cancelled shutdown. * SysV init and systemd use SIGUSR1 to restart their FIFO/D-Bus. Add API restart to SIGHUP callback for the same functionality in Finit. diff --git a/api.c b/api.c index ba1f4b79..99075f85 100644 --- a/api.c +++ b/api.c @@ -217,9 +217,14 @@ static int do_handle_emit(char *buf, size_t len) return result; } +/* + * In contrast to the SysV compat handling in plugins/initctl.c, when + * `initctl runlevel 0` is issued we default to POWERDOWN the system + * instead of just halting. + */ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events)) { - int sd; + int sd, lvl; struct init_request rq; sd = accept(w->fd, NULL, NULL); @@ -255,26 +260,19 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events)) switch (rq.cmd) { case INIT_CMD_RUNLVL: switch (rq.runlevel) { - case '0': - _d("Halting system (SIGUSR2)"); - do_shutdown(SHUT_OFF); - break; - case 's': case 'S': - _d("Cannot enter bootstrap after boot ..."); - rq.runlevel = '1'; + rq.runlevel = '1'; /* Single user mode */ /* Fall through to regular processing */ - case '1'...'5': - case '7'...'9': + case '0'...'9': _d("Setting new runlevel %c", rq.runlevel); - service_runlevel(rq.runlevel - '0'); - break; - - case '6': - _d("Rebooting system (SIGUSR1)"); - do_shutdown(SHUT_REBOOT); + lvl = rq.runlevel - '0'; + if (lvl == 0) + halt = SHUT_OFF; + if (lvl == 6) + halt = SHUT_REBOOT; + service_runlevel(lvl); break; default: diff --git a/plugins/initctl.c b/plugins/initctl.c index ebda5b7b..d1d5f81d 100644 --- a/plugins/initctl.c +++ b/plugins/initctl.c @@ -39,13 +39,6 @@ #include "../sig.h" #include "../service.h" -/* - * Old-style SysV shutdown sends a setenv cmd INIT_HALT with "=HALT", - * "=POWERDOWN", or "" to cancel shutdown, before requesting change to - * runlevel 6 over the /dev/initctl FIFO. - */ -shutop_t halt = SHUT_DEFAULT; - static void parse(void *arg, int fd, int events); static void setup(void *arg); @@ -99,11 +92,15 @@ static void set_env(char *data) } /* - * Standard reboot/shutdown utilities talk to init using /dev/initctl. + * Standard reboot/shutdown utilities talk to init using /run/initctl. * We should check if the fifo was recreated and reopen it. + * + * For SysV compatibility the default is to halt the system when issuing + * `init 0`, unless INIT_HALT=POWERDOWN, as performed by the SysV utils. */ static void parse(void *UNUSED(arg), int fd, int UNUSED(events)) { + int lvl; struct init_request rq; while (1) { @@ -132,25 +129,17 @@ static void parse(void *UNUSED(arg), int fd, int UNUSED(events)) switch (rq.cmd) { case INIT_CMD_RUNLVL: switch (rq.runlevel) { - case '0': - _d("Halting system (SIGUSR1 or SIGUSR2)"); - do_shutdown(halt); - break; - case 's': case 'S': rq.runlevel = '1'; /* Fall through to regular processing */ - case '1'...'5': - case '7'...'9': + case '0'...'9': _d("Setting new runlevel %c", rq.runlevel); - service_runlevel(rq.runlevel - '0'); - break; - - case '6': - _d("Rebooting system (SIGTERM)"); - do_shutdown(SHUT_REBOOT); + lvl = rq.runlevel - '0'; + if (lvl == 6) + halt = SHUT_REBOOT; + service_runlevel(lvl); break; default: diff --git a/sig.c b/sig.c index 3f7793a5..2dd5b5ac 100644 --- a/sig.c +++ b/sig.c @@ -80,6 +80,13 @@ #include "service.h" #include "utmp-api.h" +/* + * Old-style SysV shutdown sends a setenv cmd INIT_HALT with "=HALT", + * "=POWERDOWN", or "" to cancel shutdown, before requesting change to + * runlevel 6 over the /dev/initctl FIFO. See plugins/initctl.c + */ +shutop_t halt = SHUT_DEFAULT; + static int stopped = 0; static uev_t sigterm_watcher, sigusr1_watcher, sigusr2_watcher; static uev_t sighup_watcher, sigint_watcher, sigpwr_watcher; @@ -184,7 +191,8 @@ static void sighup_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events)) */ static void sigint_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events)) { - do_shutdown(SHUT_REBOOT); + halt = SHUT_REBOOT; + service_runlevel(6); } /* @@ -192,7 +200,8 @@ static void sigint_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events)) */ static void sigusr1_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events)) { - do_shutdown(SHUT_HALT); + halt = SHUT_HALT; + service_runlevel(0); } /* @@ -200,7 +209,8 @@ static void sigusr1_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events)) */ static void sigusr2_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events)) { - do_shutdown(SHUT_OFF); + halt = SHUT_OFF; + service_runlevel(0); } /* @@ -208,7 +218,8 @@ static void sigusr2_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events)) */ static void sigterm_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events)) { - do_shutdown(SHUT_REBOOT); + halt = SHUT_REBOOT; + service_runlevel(6); } /* diff --git a/sig.h b/sig.h index c16c21c1..e6d43e0d 100644 --- a/sig.h +++ b/sig.h @@ -66,6 +66,8 @@ typedef enum { SHUT_REBOOT } shutop_t; +extern shutop_t halt; + void do_shutdown (shutop_t op); int sig_stopped (void); void sig_init (void); diff --git a/sm.c b/sm.c index c2c7f097..fa098ed4 100644 --- a/sm.c +++ b/sm.c @@ -160,13 +160,14 @@ restart: /* Cleanup stale services */ svc_clean_dynamic(service_unregister); - if (0 == runlevel) { - do_shutdown(SHUT_OFF); - sm->state = SM_RUNNING_STATE; - break; - } - if (6 == runlevel) { - do_shutdown(SHUT_REBOOT); + /* + * "I've seen things you people wouldn't believe. Attack ships on fire off + * the shoulder of Orion. I watched C-beams glitter in the dark near the + * Tannhäuser Gate. All those .. moments .. will be lost in time, like + * tears ... in ... rain." + */ + if (runlevel == 0 || runlevel == 6) { + do_shutdown(halt); sm->state = SM_RUNNING_STATE; break; }