mirror of
https://github.com/troglobit/finit.git
synced 2026-10-02 14:02:52 +07:00
Adopt BusyBox init signal handling for halt/reboot/poweroff
This patch adopts the BusyBox init signals for handling halt, reboot, and poweroff. The SIGINT and SIGPWR signals still behave the same as before, even though they likely will become configurable in a future release. Note: the disabling of Ctrl-Alt-Delete (SIGINT) is also removed! Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
This commit is contained in:
@@ -245,12 +245,45 @@ start any new ones for you, without rebooting the system.
|
||||
Rebooting & Halting
|
||||
-------------------
|
||||
|
||||
Finit handles `SIGUSR1` and `SIGUSR2` for reboot and halt, and listens
|
||||
to `/dev/initctl` so system reboot and halt commands also work. The
|
||||
latter is implemented in the optional `initctl.so` plugin and can be
|
||||
accessed with the traditional `telinit` command line tool, symlinked to
|
||||
`finit`. Hence, if finit is your system init, then `init q` will work
|
||||
as the UNIX beards intended.
|
||||
Finit is often used on embedded and small Linux systems with BusyBox.
|
||||
For compatibility with its existing toolset (halt, poweroff, reboot),
|
||||
the following signals have been adopted:
|
||||
|
||||
* `SIGUSR1`
|
||||
Same effect as `finit q`, reloads all *.conf files in `/etc/finit.d/`
|
||||
* `SIGUSR1`
|
||||
Calls shutdown hooks, including HOOK_SHUTDOWN, stops all running
|
||||
processes, and unmounts all file systems. Then tells kernel to
|
||||
halt. Most people these days want SIGUSR2 though.
|
||||
|
||||
SysV init and systemd use this to re-open their FIFO/D-Bus.
|
||||
* `SIGUSR2`
|
||||
Like SIGUSR1, but tell kernel to power-off the system, if ACPI
|
||||
or similar exists to actually do this. If the kernel fails
|
||||
power-off, Finit falls back to halt.
|
||||
|
||||
SysV init N/A, systemd dumps its internal state to log.
|
||||
* `SIGTERM`
|
||||
Like `SIGUSR1`, but tell kernel to reboot the system when done.
|
||||
|
||||
SysV init N/A, systemd rexecutes itself.
|
||||
* `SIGINT`
|
||||
Sent from kernel when the CTRL-ALT-DEL key combo is pressed.
|
||||
SysV init and systemd default to reboot with `shutdown -r`.
|
||||
Finit currently forwards this to `SIGTERM`.
|
||||
* `SIGPWR`
|
||||
Sent from a power daemon, like `powstatd(8)`, on changes to the
|
||||
UPS status. Traditionally SysV init read /etc/powerstatus and
|
||||
acted on "OK", "FAIL", or "LOW" and then removed the file.
|
||||
Finit currently forwards this to `SIGUSR2`.
|
||||
|
||||
Finit also listens to the classic SysV init FIFO, which used to be
|
||||
located in `/dev` but these days default to `/run/initctl`. So existing
|
||||
tools like, `poweroff`, `halt`, `reboot`, and `shutdown` work as
|
||||
expected. Support for this old-style handling is implemented in the
|
||||
optional `initctl.so` plugin and can be accessed with the traditional
|
||||
`telinit` command line tool, symlinked to `finit`. Hence, if finit is
|
||||
your system init, then `init q` will work as the UNIX beards intended.
|
||||
|
||||
```shell
|
||||
~ $ telinit
|
||||
|
||||
@@ -18,6 +18,17 @@ very low dependency on external packages.
|
||||
General
|
||||
-------
|
||||
|
||||
* Add halt/poweroff/shutdown symlinks to finit and convert reboot, but
|
||||
only install symlinks if these tools don't already exist.
|
||||
* Add reboot, halt, poweroff commands to `initctl` tool
|
||||
* SysV init and systemd use SIGUSR1 to restart their FIFO/D-Bus. Add
|
||||
API restart to SIGHUP callback for the same functionality in Finit.
|
||||
* Add `finit.conf` support for UPS notification (SIGPWR) to start a task
|
||||
using, e.g. <sys/power/{ok,fail,low}> conditions. More info in sig.c
|
||||
* Add `finit.conf` support for ctrl-alt-delete (SIGINT) and kbrequest,
|
||||
i.e. KeyboardSignal, (SIGWINCH) behavior. Using conditions to a task,
|
||||
e.g, <sys/key/ctrlaltdel> and <sys/key/signal> like SIGPWR handling.
|
||||
* Add `IFF_RUNNING` support to netlink plugin along `IFF_IUP`
|
||||
* Add compile-time support for running `/bin/sh` instead of `getty`
|
||||
* Add `!` or `[wait <pidfile>]` to service directive to let finit pause
|
||||
and wait for a pidfile before starting processes -- both at boot and
|
||||
|
||||
@@ -255,7 +255,7 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
|
||||
switch (rq.runlevel) {
|
||||
case '0':
|
||||
_d("Halting system (SIGUSR2)");
|
||||
do_shutdown(SIGUSR2);
|
||||
do_shutdown(SHUT_OFF);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
@@ -272,7 +272,7 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
|
||||
|
||||
case '6':
|
||||
_d("Rebooting system (SIGUSR1)");
|
||||
do_shutdown(SIGUSR1);
|
||||
do_shutdown(SHUT_REBOOT);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -21,21 +21,47 @@
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* The standard SysV init only responds to the following signals:
|
||||
* SIGHUP
|
||||
* Has the same effect as telinit q.
|
||||
* Finit is often used on embedded and small Linux systems with BusyBox.
|
||||
* For compatibility with its existing toolset (halt, poweroff, reboot),
|
||||
* the following signals have been adopted:
|
||||
*
|
||||
* SIGUSR1
|
||||
* On receipt of this signals, init closes and re-opens its control
|
||||
* fifo, /dev/initctl. Useful for bootscripts when /dev is remounted.
|
||||
* SIGHUP
|
||||
* Same effect as init/telinit q, reloads *.conf in /etc/finit.d/
|
||||
*
|
||||
* SIGINT
|
||||
* Normally the kernel sends this signal to init when CTRL-ALT-DEL is
|
||||
* pressed. It activates the ctrlaltdel action.
|
||||
* SIGUSR1
|
||||
* Calls shutdown hooks, including HOOK_SHUTDOWN, stops all running
|
||||
* processes, and unmounts all file systems. Then tells kernel to
|
||||
* halt. Most people these days want SIGUSR2 though.
|
||||
*
|
||||
* SIGWINCH
|
||||
* The kernel sends this signal when the KeyboardSignal key is hit.
|
||||
* It activates the kbrequest action.
|
||||
* (SysV init and systemd use this to re-open their FIFO/D-Bus.)
|
||||
*
|
||||
* SIGUSR2
|
||||
* Like SIGUSR1, but tell kernel to power-off the system, if ACPI
|
||||
* or similar exists to actually do this. If the kernel fails
|
||||
* power-off, Finit falls back to halt.
|
||||
*
|
||||
* (SysV init N/A, systemd dumps its internal state to log.)
|
||||
*
|
||||
* SIGTERM
|
||||
* Like SIGUSR1, but tell kernel to reboot the system when done.
|
||||
*
|
||||
* (SysV init N/A, systemd rexecutes itself.)
|
||||
*
|
||||
* SIGINT
|
||||
* Sent from kernel when the CTRL-ALT-DEL key combo is pressed.
|
||||
* SysV init and systemd default to reboot with `shutdown -r`.
|
||||
* Finit currently forwards this to SIGTERM.
|
||||
*
|
||||
* SIGWINCH
|
||||
* Sent from kernel when the KeyboardSignal key is pressed. Some
|
||||
* users bind keys, see loadkeys(1), to create consoles on demand.
|
||||
* Finit currently ignores this signal.
|
||||
*
|
||||
* SIGPWR
|
||||
* Sent from a power daemon, like powstatd(8), on changes to the
|
||||
* UPS status. Traditionally SysV init read /etc/powerstatus and
|
||||
* acted on "OK", "FAIL", or "LOW" and then removed the file.
|
||||
* Finit currently forwards this to SIGUSR2.
|
||||
*/
|
||||
|
||||
#include <sched.h>
|
||||
@@ -54,12 +80,13 @@
|
||||
#include "service.h"
|
||||
|
||||
static int stopped = 0;
|
||||
static uev_t sighup_watcher, sigint_watcher, sigpwr_watcher;
|
||||
static uev_t sigterm_watcher, sigusr1_watcher, sigusr2_watcher;
|
||||
static uev_t sighup_watcher, sigint_watcher, sigpwr_watcher;
|
||||
static uev_t sigchld_watcher, sigsegv_watcher;
|
||||
static uev_t sigstop_watcher, sigtstp_watcher, sigcont_watcher;
|
||||
|
||||
|
||||
void do_shutdown(int sig)
|
||||
void do_shutdown(shutop_t op)
|
||||
{
|
||||
touch(SYNC_SHUTDOWN);
|
||||
|
||||
@@ -121,15 +148,18 @@ void do_shutdown(int sig)
|
||||
run("/bin/mount -n -o remount,ro dummydev /");
|
||||
run("/bin/mount -n -o remount,ro /");
|
||||
|
||||
_e("PID %d: %s ...", getpid(), sig == SIGINT || sig == SIGUSR1 ? "Rebooting" : "Halting");
|
||||
_e("PID %d: %s ...", getpid(), op == SHUT_REBOOT ? "Rebooting" : "Halting");
|
||||
do_sleep(5);
|
||||
|
||||
_d("%s.", sig == SIGINT || sig == SIGUSR1 ? "Rebooting" : "Halting");
|
||||
if (sig == SIGINT || sig == SIGUSR1)
|
||||
_d("%s.", op == SHUT_REBOOT ? "Rebooting" : "Halting");
|
||||
if (op == SHUT_REBOOT)
|
||||
reboot(RB_AUTOBOOT);
|
||||
|
||||
reboot(RB_POWER_OFF);
|
||||
reboot(RB_HALT_SYSTEM); /* Eh, what? Should not get here ... */
|
||||
if (op == SHUT_OFF)
|
||||
reboot(RB_POWER_OFF);
|
||||
|
||||
/* Also fallback if any of the other two fails */
|
||||
reboot(RB_HALT_SYSTEM);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -142,11 +172,35 @@ static void sighup_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||
}
|
||||
|
||||
/*
|
||||
* Shut down on INT PWR
|
||||
* SIGINT: Should generate <sys/key/ctrlaltdel> condition, for now reboot
|
||||
*/
|
||||
static void sigint_cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
|
||||
static void sigint_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||
{
|
||||
do_shutdown(w->signo);
|
||||
do_shutdown(SHUT_REBOOT);
|
||||
}
|
||||
|
||||
/*
|
||||
* SIGUSR1: BusyBox style halt
|
||||
*/
|
||||
static void sigusr1_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||
{
|
||||
do_shutdown(SHUT_HALT);
|
||||
}
|
||||
|
||||
/*
|
||||
* SIGUSR2: BusyBox style poweroff
|
||||
*/
|
||||
static void sigusr2_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||
{
|
||||
do_shutdown(SHUT_OFF);
|
||||
}
|
||||
|
||||
/*
|
||||
* SIGTERM: BusyBox style reboot
|
||||
*/
|
||||
static void sigterm_cb(uev_t *UNUSED(w), void *UNUSED(arg), int UNUSED(events))
|
||||
{
|
||||
do_shutdown(SHUT_REBOOT);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -237,6 +291,9 @@ void sig_unblock(void)
|
||||
sigaddset(&nmask, SIGSTOP);
|
||||
sigaddset(&nmask, SIGTSTP);
|
||||
sigaddset(&nmask, SIGCONT);
|
||||
sigaddset(&nmask, SIGTERM);
|
||||
sigaddset(&nmask, SIGUSR1);
|
||||
sigaddset(&nmask, SIGUSR2);
|
||||
sigprocmask(SIG_UNBLOCK, &nmask, NULL);
|
||||
|
||||
/* Reset signal handlers that were set by the parent process */
|
||||
@@ -261,12 +318,10 @@ void sig_setup(uev_ctx_t *ctx)
|
||||
uev_signal_init(ctx, &sigint_watcher, sigint_cb, NULL, SIGINT);
|
||||
uev_signal_init(ctx, &sigpwr_watcher, sigint_cb, NULL, SIGPWR);
|
||||
|
||||
/* Ignore SIGUSR1/2 for now, only BusyBox init implements them as reboot+halt. */
|
||||
// uev_signal_init(&ctx, &sigusr1_watcher, reopen_initctl_cb, NULL, SIGUSR1);
|
||||
// uev_signal_init(&ctx, &sigusr2_watcher, pwrdwn_cb, NULL, SIGUSR2);
|
||||
|
||||
/* Init must ignore SIGTERM. May otherwise get false SIGTERM in forked children! */
|
||||
IGNSIG(sa, SIGTERM, 0);
|
||||
/* BusyBox init style signals for halt, power-off and reboot. */
|
||||
uev_signal_init(ctx, &sigusr1_watcher, sigusr1_cb, NULL, SIGUSR1);
|
||||
uev_signal_init(ctx, &sigusr2_watcher, sigusr2_cb, NULL, SIGUSR2);
|
||||
uev_signal_init(ctx, &sigterm_watcher, sigterm_cb, NULL, SIGTERM);
|
||||
|
||||
/* Some C APIs may need SIGALRM for implementing timers. */
|
||||
IGNSIG(sa, SIGALRM, 0);
|
||||
@@ -285,8 +340,6 @@ void sig_setup(uev_ctx_t *ctx)
|
||||
uev_signal_init(ctx, &sigtstp_watcher, sigstop_cb, NULL, SIGTSTP);
|
||||
uev_signal_init(ctx, &sigcont_watcher, sigcont_cb, NULL, SIGCONT);
|
||||
|
||||
/* Disable CTRL-ALT-DELETE from kernel, we handle shutdown gracefully with SIGINT, above */
|
||||
reboot(RB_DISABLE_CAD);
|
||||
setsid();
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,13 @@
|
||||
sigaction(sig, &sa, NULL); \
|
||||
} while (0)
|
||||
|
||||
void do_shutdown (int sig);
|
||||
typedef enum {
|
||||
SHUT_OFF,
|
||||
SHUT_HALT,
|
||||
SHUT_REBOOT
|
||||
} shutop_t;
|
||||
|
||||
void do_shutdown (shutop_t op);
|
||||
int sig_stopped (void);
|
||||
void sig_init (void);
|
||||
void sig_unblock (void);
|
||||
|
||||
@@ -155,12 +155,12 @@ restart:
|
||||
svc_clean_dynamic(service_unregister);
|
||||
|
||||
if (0 == runlevel) {
|
||||
do_shutdown(SIGUSR2);
|
||||
do_shutdown(SHUT_OFF);
|
||||
sm->state = SM_RUNNING_STATE;
|
||||
break;
|
||||
}
|
||||
if (6 == runlevel) {
|
||||
do_shutdown(SIGUSR1);
|
||||
do_shutdown(SHUT_REBOOT);
|
||||
sm->state = SM_RUNNING_STATE;
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user