Fix #147: refactor reboot as multi-call to initctl

This patch drops the stand-alone reboot binary and folds it into the
initctl tool, which now becomes a multi-call binary.

With this change the reboot/shutdown/poweroff/halt/suspend commands also
no longer default to sending signals to PID 1, instead it now uses the
initctl <--> finit UNIX domain socket API.  Signals are only used as a
fallback in case of non-working domain socket.  The -f,--force mode of
operation still works, where `reboot(2)` is called directly.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg
2021-02-21 10:59:08 +01:00
parent 649a269526
commit 7e42203627
4 changed files with 117 additions and 66 deletions
+5
View File
@@ -12,6 +12,11 @@ to service conditions. There are other significant changes as well, so
make sure to read the whole changelog when upgrading.
### Changes
* The stand-alone `reboot` tool has been replaced with a symlink to
`initctl`, like its siblings: halt, shutdown, poweroff, and suspend.
Calling `reboot` & C:o now defaults to the corresponding `initctl cmd`
with a fallback to sending signals as per traditional SysV init. The
`-f` (force) flag remains, where `reboot(2)` is called directly
* Introducing Finit progress 𝓜𝓸𝓭𝓮𝓻𝓷
* Removed built-in inetd super server. If you need this functionality,
use an external inetd, like xinetd, instead. A pull request for a
+34 -46
View File
@@ -8,7 +8,7 @@ else
AM_LDFLAGS = -export-dynamic
endif
sbin_PROGRAMS = finit initctl reboot
sbin_PROGRAMS = finit initctl
pkglibexec_SCRIPTS = cgreaper.sh
if WATCHDOGD
pkglibexec_PROGRAMS = watchdogd
@@ -49,19 +49,15 @@ else
finit_LDADD += -ldl
endif
initctl_SOURCES = initctl.c client.c client.h \
serv.c serv.h svc.h \
initctl_SOURCES = initctl.c client.c client.h \
reboot.c serv.c serv.h svc.h \
cond.c cond.h util.c util.h
initctl_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
initctl_CFLAGS += $(lite_CFLAGS)
initctl_LDADD = $(lite_LIBS)
reboot_SOURCES = reboot.c util.c util.h
reboot_CFLAGS = $(lite_CFLAGS)
reboot_LDADD = $(lite_LIBS)
INIT_LNKS = init
REBOOT_LNKS = shutdown halt poweroff suspend
REBOOT_LNKS = reboot shutdown halt poweroff suspend
if WATCHDOGD
watchdogd_SOURCES = watchdog.c watchdog.h
@@ -72,46 +68,38 @@ endif
# Hook in install to add finit and reboot symlink(s)
install-exec-hook:
@$(INSTALL_DATA) $(srcdir)/rescue.conf $(DESTDIR)$(pkglibdir)
@for file in $(INIT_LNKS); do \
lnk=$(DESTDIR)$(sbindir)/$$file; \
if [ -e $$lnk ]; then \
echo "Skipping $$lnk exists."; \
else \
$(LN_S) finit $$lnk; \
fi; \
@for file in $(INIT_LNKS); do \
lnk=$(DESTDIR)$(sbindir)/$$file; \
if [ -e $$lnk ]; then \
echo "Skipping $$lnk exists."; \
else \
$(LN_S) finit $$lnk; \
fi; \
done
@for file in $(REBOOT_LNKS); do \
lnk=$(DESTDIR)$(sbindir)/$$file; \
if [ -e $$lnk ]; then \
echo "Skipping $$lnk exists."; \
else \
$(LN_S) initctl $$lnk; \
fi; \
done
@if [ -L $(DESTDIR)$(sbindir)/reboot ]; then \
echo "Non-finit reboot, skipping install."; \
else \
for file in $(REBOOT_LNKS); do \
lnk=$(DESTDIR)$(sbindir)/$$file; \
if [ -e $$lnk ]; then \
echo "Skipping $$lnk exists."; \
else \
$(LN_S) reboot $$lnk; \
fi; \
done; \
fi
uninstall-hook:
@$(RM) $(DESTDIR)$(pkglibdir)/rescue.conf
@for file in $(INIT_LNKS); do \
lnk=`readlink $(DESTDIR)$(sbindir)/$$file`; \
if [ "$$lnk" != "finit" ]; then \
echo "Skipping non-finit $$file."; \
continue; \
fi; \
$(RM) $(DESTDIR)$(sbindir)/$$file; \
@for file in $(INIT_LNKS); do \
lnk=$(DESTDIR)$(sbindir)/$$file; \
dst=`readlink $$lnk`; \
if [ "$$dst" != "finit" ]; then \
continue; \
fi; \
$(RM) $(DESTDIR)$(sbindir)/$$file; \
done
@for file in $(REBOOT_LNKS); do \
lnk=$(DESTDIR)$(sbindir)/$$file; \
dst=`readlink $$lnk`; \
if [ "$$dst" != "initctl" ]; then \
continue; \
fi; \
$(RM) $$lnk; \
done
@if [ -L $(DESTDIR)$(sbindir)/reboot ]; then \
echo "Non-finit reboot, skipping uninstall."; \
else \
for file in $(REBOOT_LNKS); do \
lnk=$(DESTDIR)$(sbindir)/$$file; \
dst=`readlink $$lnk`; \
if [ "$$dst" != "reboot" ]; then \
continue; \
fi; \
$(RM) $$lnk; \
done; \
fi
+44 -8
View File
@@ -54,6 +54,9 @@ int verbose = 0;
int runlevel = 0;
int iw, pw;
extern int reboot_main(int argc, char *argv[]);
/* figure ut width of IDENT and PID columns */
static void col_widths(void)
{
@@ -349,17 +352,30 @@ static int do_cond(char *cmd)
return do_cond_show(NULL);
}
static int do_signal(int signo, const char *msg)
static int do_cmd(int cmd)
{
if (kill(1, signo))
err(1, "Failed signalling init to %s", msg);
struct init_request rq = {
.magic = INIT_MAGIC,
.cmd = cmd,
};
if (client_send(&rq, sizeof(rq))) {
if (rq.cmd == INIT_CMD_NACK)
puts(rq.data);
return 1;
}
/* Wait here for systemd to shutdown/reboot */
sleep(5);
return 0;
}
static int do_halt (char *arg) { return do_signal(SIGUSR1, "halt"); }
static int do_poweroff(char *arg) { return do_signal(SIGUSR2, "power off"); }
static int do_reboot (char *arg) { return do_signal(SIGTERM, "reboot"); }
int do_reboot (char *arg) { return do_cmd(INIT_CMD_REBOOT); }
int do_halt (char *arg) { return do_cmd(INIT_CMD_HALT); }
int do_poweroff(char *arg) { return do_cmd(INIT_CMD_POWEROFF); }
int do_suspend (char *arg) { return do_cmd(INIT_CMD_SUSPEND); }
int utmp_show(char *file)
{
@@ -605,6 +621,22 @@ static int show_cgroup(char *arg)
return 0;
}
static int transform(char *nm)
{
char *names[] = {
"reboot", "shutdown", "poweroff", "halt", "suspend",
NULL
};
size_t i;
for (i = 0; names[i]; i++) {
if (!strcmp(nm, names[i]))
return 1;
}
return 0;
}
static int usage(int rc)
{
fprintf(stderr,
@@ -644,7 +676,8 @@ static int usage(int rc)
" runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n"
" reboot Reboot system\n"
" halt Halt system\n"
" poweroff Halt and power off system\n", prognm);
" poweroff Halt and power off system\n"
" suspend Suspend system\n", prognm);
if (has_utmp())
fprintf(stderr,
@@ -693,6 +726,7 @@ int main(int argc, char *argv[])
{ "reboot", do_reboot },
{ "halt", do_halt },
{ "poweroff", do_poweroff },
{ "suspend", do_suspend },
{ "utmp", do_utmp },
{ NULL, NULL }
@@ -706,7 +740,9 @@ int main(int argc, char *argv[])
{ NULL, 0, NULL, 0 }
};
progname(argv[0]);
if (transform(progname(argv[0])))
return reboot_main(argc, argv);
while ((c = getopt_long(argc, argv, "bh?ntv", long_options, NULL)) != EOF) {
switch(c) {
case 'b':
+34 -12
View File
@@ -22,6 +22,7 @@
*/
#include <err.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <stdio.h>
@@ -40,6 +41,13 @@ typedef enum {
static cmd_t cmd = CMD_UNKNOWN;
static char *msg = NULL;
/* initctl API */
extern int do_reboot (char *arg);
extern int do_halt (char *arg);
extern int do_poweroff(char *arg);
extern int do_suspend (char *arg);
static void transform(char *nm)
{
if (!nm)
@@ -80,6 +88,16 @@ static void transform(char *nm)
}
}
/*
* fallback in case of initctl API failure
*/
static void do_kill(int signo, char *msg)
{
if (kill(1, signo))
err(1, "Failed signalling init to %s", msg);
do_sleep(5);
}
static void sig(int signo)
{
(void)signo; /* NOP */
@@ -100,7 +118,7 @@ static int usage(int rc)
return rc;
}
int main(int argc, char *argv[])
int reboot_main(int argc, char *argv[])
{
int c, force = 0;
struct option long_options[] = {
@@ -113,7 +131,7 @@ int main(int argc, char *argv[])
};
/* Initial command taken from program name */
transform(progname(argv[0]));
transform(prognm);
while ((c = getopt_long(argc, argv, "h?fHPpr", long_options, NULL)) != EOF) {
switch(c) {
@@ -165,6 +183,8 @@ int main(int argc, char *argv[])
case CMD_SUSPEND:
c = reboot(RB_SW_SUSPEND);
if (c && errno == EINVAL)
errx(1, "Kernel does not support suspend.");
break;
case CMD_UNKNOWN:
@@ -173,22 +193,25 @@ int main(int argc, char *argv[])
}
if (c)
warn("Failed forced %s", msg);
else
return 0;
err(1, "Failed forced %s", msg);
return 0;
}
switch (cmd) {
case CMD_REBOOT:
c = kill(1, SIGTERM);
if (do_reboot(NULL))
do_kill(SIGTERM, msg);
break;
case CMD_HALT:
c = kill(1, SIGUSR1);
if (do_halt(NULL))
do_kill(SIGUSR1, msg);
break;
case CMD_POWEROFF:
c = kill(1, SIGUSR2);
if (do_poweroff(NULL))
do_kill(SIGUSR2, msg);
break;
case CMD_SUSPEND:
@@ -196,16 +219,15 @@ int main(int argc, char *argv[])
* Only initctl supports suspend, we avoid adding
* another signal to finit for compat reasons.
*/
do_suspend(NULL);
break;
case CMD_UNKNOWN:
errx(1, "Invalid command");
break;
}
if (c)
err(1, "Failed signalling init to %s", msg);
do_sleep(5);
return 0;
}