From cb64c068e3d1874d762b8e3cfb0c48ea0eab1b4c Mon Sep 17 00:00:00 2001 From: Jacques de Laval Date: Thu, 11 Feb 2021 17:25:56 +0100 Subject: [PATCH] Fix #136: drop old init client tool The SysV API compatibility layer gives too little value to be worth the effort of maintaining it. Users are encouraged to use the `initctl` tool instead. Signed-off-by: Jacques de Laval --- README.md | 29 +------ configure.ac | 11 --- doc/plugins.md | 10 +-- plugins/Makefile.am | 4 +- plugins/initctl.c | 194 -------------------------------------------- src/Makefile.am | 3 +- src/api.c | 6 -- src/finit.c | 12 +-- src/finit.h | 6 +- src/initctl.c | 2 +- src/private.h | 2 - src/sig.c | 4 +- src/telinit.c | 159 ------------------------------------ 13 files changed, 20 insertions(+), 422 deletions(-) delete mode 100644 plugins/initctl.c delete mode 100644 src/telinit.c diff --git a/README.md b/README.md index 212074e0..d205bb38 100644 --- a/README.md +++ b/README.md @@ -385,42 +385,19 @@ Rebooting & Halting Traditionally, rebooting and halting a UNIX system is done by changing its runlevel. Finit comes with its own tooling providing: `shutdown`, -`reboot`, `poweroff`, and `suspend`, but also the traditional `init` and -`telinit`, as well as a more modern `initctl` tool, detailed in the next -section. +`reboot`, `poweroff`, and `suspend`, but also the `initctl` tool, +detailed in the next section. For compatibility reasons Finit listens to the same set of signals as BusyBox init. This is not 100% compatible with SysV init, but clearly the more common combination for Finit. For more details, see [doc/signals.md](doc/signals.md). -Finit also listens to the classic SysV init FIFO, used by `telinit`. -Support for this is implemented by the `initctl.so` plugin. Hence, -`telinit q` will work as the UNIX beards intended. - -```shell -~ # telinit -h -Usage: telinit [OPTIONS] [q | Q | 0-9] - -Options: - -h, --help This help text - -V, --version Show Finit version - -Commands: - 0 Power-off the system, same as initctl poweroff - 6 Reboot the system, same as initctl reboot - 2, 3, 4, 5 Change runlevel. Starts services in new runlevel, stops any - services in prev. runlevel that are not allowed in new. - q, Q Reload *.conf in /etc/finit.d/, same as initctl reload or - sending SIGHUP to PID 1 - 1, s, S Enter system rescue mode, runlevel 1 -``` - Commands & Status ----------------- -Finit also implements a more modern API to query status, and start/stop +Finit also implements a modern API to query status, and start/stop services, called `initctl`. Unlike `telinit` the `initctl` tool does not return until the given command has fully completed. diff --git a/configure.ac b/configure.ac index 212b5aa4..9bcd110a 100644 --- a/configure.ac +++ b/configure.ac @@ -105,10 +105,6 @@ AC_ARG_WITH(heading, AS_HELP_STRING([--with-heading=GREET], [Display GREET instead of Finit version at boot]), [heading=$withval], [heading="$PACKAGE_NAME v$PACKAGE_VERSION"]) -AC_ARG_WITH(fifo, - AS_HELP_STRING([--with-fifo=FIFO], [FIFO for init/telinit clients, default /var/run/initctl]), - [fifo=$withval], [fifo=$localstatedir/run/initctl]) - AC_ARG_WITH(config, AS_HELP_STRING([--with-config=CONFIG], [Finit bootstrap config file, default /etc/finit.conf]), [conf=$withval], [conf=$sysconfdir/finit.conf]) @@ -172,12 +168,6 @@ AS_IF([test "x$enable_logrotate" != "xno"], [ AC_DEFINE(LOGROTATE_ENABLED, 1, [Enable built-in rotation of /var/log/wtmp et al.])]) ### With features ############################################################################## -AS_IF([test "x$with_fifo" != "xno"], [ - AS_IF([test "x$fifo" = "xyes"], [ - fifo='$localstatedir/run/initctl'])]) -AC_EXPAND_DIR(fifo_path, "$fifo") -AC_DEFINE_UNQUOTED(FINIT_FIFO, "$fifo_path", [FIFO for old style init/telinit client programs]) - AS_IF([test "x$with_config" != "xno"], [ AS_IF([test "x$config" = "xyes"], [ conf=$sysconfdir/finit.conf])]) @@ -248,7 +238,6 @@ cat < - * Copyright (c) 2008-2021 Joachim Wiberg - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "config.h" /* Generated by configure script */ - -#include -#include /* O_RDONLY et al */ -#include -#include -#include /* read() */ -#include -#include - -#include "finit.h" -#include "conf.h" -#include "helpers.h" -#include "plugin.h" -#include "sig.h" -#include "service.h" - -static void parse(void *arg, int fd, int events); -static void setup(void *arg); - -static plugin_t plugin = { - .name = __FILE__, - .io = { - .cb = parse, - .flags = PLUGIN_IO_READ, - }, - .hook[HOOK_BASEFS_UP] = { - .cb = setup - }, - .depends = { "bootmisc", }, -}; - -static void fifo_open(void) -{ - plugin.io.fd = open(FINIT_FIFO, O_RDWR | O_NONBLOCK | O_CLOEXEC); - if (-1 == plugin.io.fd) { - _e("Failed opening %s FIFO, error %d: %s", FINIT_FIFO, errno, strerror(errno)); - return; - } -} - -/* - * We only handle INIT_HALT for differentiating between halt/poweroff - */ -static void set_env(char *data) -{ - const char *var = "INIT_HALT"; - - if (strncmp(data, var, strlen(var))) - return; - data += strlen(var); - - /* - * No value means unset env, in this case cancel shutdown. - */ - if (data[0] == 0) { - halt = SHUT_DEFAULT; - /* XXX: Cancel timer here, when we get support for timed shutdown */ - return; - } - - if (string_match(data, "=POWERDOWN")) - halt = SHUT_OFF; - if (string_match(data, "=HALT")) - halt = SHUT_HALT; - - /* Now we wait for runlevel change, or cancelled shutdown */ -} - -/* - * 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 *arg, int fd, int events) -{ - int lvl; - struct init_request rq; - - while (1) { - ssize_t len = read(fd, &rq, sizeof(rq)); - - if (len <= 0) { - if (-1 == len) { - if (EINTR == errno) - continue; - - if (EAGAIN == errno) - break; - - _e("Failed reading initctl request, error %d: %s", errno, strerror(errno)); - } - - _d("Nothing to do, bailing out."); - break; - } - - if (rq.magic != INIT_MAGIC || len != sizeof(rq)) { - _e("Invalid initctl request."); - break; - } - - switch (rq.cmd) { - case INIT_CMD_RUNLVL: - switch (rq.runlevel) { - case 's': - case 'S': - rq.runlevel = '1'; /* Single user mode */ - /* fallthrough */ - - case '0'...'9': - _d("Setting new runlevel %c", rq.runlevel); - lvl = rq.runlevel - '0'; - if (lvl == 6) - halt = SHUT_REBOOT; - service_runlevel(lvl); - break; - - default: - _d("Unsupported runlevel: %d", rq.runlevel); - break; - } - break; - - case INIT_CMD_RELOAD: - service_reload_dynamic(); - break; - - case INIT_CMD_SETENV: - set_env(rq.data); - break; - - default: - _d("Unsupported cmd: %d", rq.cmd); - break; - } - } - - close(fd); - fifo_open(); -} - -/* Must run after the base FS is up, needs /run, or /var/run */ -static void setup(void *arg) -{ - _d("Setting up %s", FINIT_FIFO); - makefifo(FINIT_FIFO, 0600); - - fifo_open(); - plugin_io_init(&plugin); -} - -PLUGIN_INIT(plugin_init) -{ - plugin_register(&plugin); -} - -PLUGIN_EXIT(plugin_exit) -{ - plugin_unregister(&plugin); -} - -/** - * Local Variables: - * indent-tabs-mode: t - * c-file-style: "linux" - * End: - */ diff --git a/src/Makefile.am b/src/Makefile.am index c8464fcf..5e873a53 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,7 +22,6 @@ endif finit_SOURCES = api.c cgroup.c cgroup.h \ cond.c cond-w.c cond.h \ - telinit.c \ conf.c conf.h \ exec.c finit.c finit.h \ getty.c stty.c \ @@ -61,7 +60,7 @@ reboot_SOURCES = reboot.c util.c util.h reboot_CFLAGS = $(lite_CFLAGS) reboot_LDADD = $(lite_LIBS) -INIT_LNKS = telinit init +INIT_LNKS = init REBOOT_LNKS = shutdown halt poweroff suspend if WATCHDOGD diff --git a/src/api.c b/src/api.c index 35ac920c..a647e3be 100644 --- a/src/api.c +++ b/src/api.c @@ -183,12 +183,6 @@ static void send_svc(int sd, svc_t *svc) _d("Failed sending svc_t to client"); } - -/* - * 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 api_cb(uev_t *w, void *arg, int events) { int sd, lvl; diff --git a/src/finit.c b/src/finit.c index aa40aabf..3c9c6c4a 100644 --- a/src/finit.c +++ b/src/finit.c @@ -368,12 +368,12 @@ int main(int argc, char *argv[]) }; uev_ctx_t loop; - /* - * finit/init/telinit client tool uses /dev/initctl pipe - * for compatibility but initctl client tool uses socket - */ - if (getpid() != 1) - return client(argc, argv); + if (getpid() != 1) { + fprintf(stderr, "Running Finit as anything other than PID 1 " + "is not supported.\n" + "The initctl tool is the new command line API.\n"); + return 1; + } /* * Need /dev, /proc, and /sys for console=, remount and cgroups diff --git a/src/finit.h b/src/finit.h index 4df43b29..a29c2920 100644 --- a/src/finit.h +++ b/src/finit.h @@ -49,11 +49,7 @@ #define LINE_SIZE 1024 #define BUF_SIZE 4096 -/* - * We extend the INIT_CMD_ range for the new initctl tool, Finit only - * support changing runlevel, reloading the configuration and setenv - * with the old-style /dev/initctl FIFO. - */ +/* We extend the INIT_CMD_ range for the new initctl tool. */ #define INIT_SOCKET _PATH_VARRUN "finit/socket" #define INIT_MAGIC 0x03091969 diff --git a/src/initctl.c b/src/initctl.c index ca97d881..f860410b 100644 --- a/src/initctl.c +++ b/src/initctl.c @@ -1,4 +1,4 @@ -/* New client tool, complements old /dev/initctl API and telinit tool +/* New client tool, replaces old /dev/initctl API and telinit tool * * Copyright (c) 2015-2021 Joachim Wiberg * diff --git a/src/private.h b/src/private.h index 5849cd8c..41545a2d 100644 --- a/src/private.h +++ b/src/private.h @@ -31,8 +31,6 @@ int api_init (uev_ctx_t *ctx); int api_exit (void); -int client (int argc, char *argv[]); - void service_monitor (pid_t lost, int status); const char *plugin_hook_str(hook_point_t no); diff --git a/src/sig.c b/src/sig.c index a9920399..8e5758f7 100644 --- a/src/sig.c +++ b/src/sig.c @@ -26,7 +26,7 @@ * the following signals have been adopted: * * SIGHUP - * Same effect as init/telinit q, reloads *.conf in /etc/finit.d/ + * Same effect as initctl reload, reloads *.conf in /etc/finit.d/ * Also restarts API (initctl) socket, like SysV init and systemd * does on USR1 with their FIFO/D-Bus. * @@ -88,7 +88,7 @@ extern svc_t *wdog; /* * 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 + * runlevel 6 over the /dev/initctl FIFO. */ shutop_t halt = SHUT_DEFAULT; diff --git a/src/telinit.c b/src/telinit.c deleted file mode 100644 index 0598cf91..00000000 --- a/src/telinit.c +++ /dev/null @@ -1,159 +0,0 @@ -/* Simple telinit client - * - * Copyright (c) 2008-2010 Claudio Matsuoka - * Copyright (c) 2008-2021 Joachim Wiberg - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "config.h" /* Generated by configure script */ - -#include -#include -#include -#include - -#include "finit.h" -#include "util.h" - -static int do_send(struct init_request *rq) -{ - static int fd = -1; - int result = 255; - ssize_t len; - - if (fd == -1) { - if (!fexist(FINIT_FIFO)) { - fprintf(stderr, "%s does not support %s!\n", prognm, FINIT_FIFO); - return 1; - } - - fd = open(FINIT_FIFO, O_RDWR); - if (-1 == fd) { - perror("Failed opening " FINIT_FIFO); - return 1; - } - } - - len = write(fd, rq, sizeof(*rq)); - if (sizeof(*rq) == len) - result = 0; - - return result; -} - -static int do_reload(void) -{ - struct init_request rq = { - .magic = INIT_MAGIC, - .cmd = INIT_CMD_RELOAD, - }; - - return do_send(&rq); -} - -static int set_env(int runlevel) -{ - struct init_request rq = { - .magic = INIT_MAGIC, - .cmd = INIT_CMD_SETENV, - }; - - if (runlevel == 0) { - strlcpy(rq.data, "INIT_HALT=POWERDOWN", sizeof(rq.data)); - return do_send(&rq); - } - - return 0; -} - -static int set_runlevel(int runlevel) -{ - struct init_request rq = { - .magic = INIT_MAGIC, - .cmd = INIT_CMD_RUNLVL, - .runlevel = runlevel, - }; - - return set_env(runlevel) || do_send(&rq); -} - -/* telinit q | telinit <0-9> */ -static int usage(int rc) -{ - fprintf(stderr, "Usage: %s [OPTIONS] [q | Q | 0-9]\n\n" - "Options:\n" - " -h, --help This help text\n" - " -V, --version Show Finit version\n\n" - "Commands:\n" - " 0 Power-off the system, same as initctl poweroff\n" - " 6 Reboot the system, same as initctl reboot\n" - " 2, 3, 4, 5 Change runlevel. Starts services in new runlevel, stops any\n" - " services in prev. runlevel that are not allowed in new.\n" - " q, Q Reload *.conf in /etc/finit.d/, same as initctl reload or\n" - " sending SIGHUP to PID 1\n" - " 1, s, S Enter system rescue mode, runlevel 1\n" - "\n", prognm); - - return rc; -} - -int client(int argc, char *argv[]) -{ - int c; - struct option long_options[] = { - {"help", 0, NULL, 'h'}, - {"version", 0, NULL, 'v'}, - {NULL, 0, NULL, 0} - }; - - progname(argv[0]); - while ((c = getopt_long(argc, argv, "h?v", long_options, NULL)) != EOF) { - switch(c) { - case 'v': - return puts("v" VERSION) == EOF; - - case 'h': - case '?': - return usage(0); - } - } - - if (optind < argc) { - int req = (int)argv[optind][0]; - - if (isdigit(req)) - return set_runlevel(req); - - if (req == 'q' || req == 'Q') - return do_reload(); - - if (req == 's' || req == 'S') - return set_runlevel(1); - } - - return usage(1); -} - -/** - * Local Variables: - * indent-tabs-mode: t - * c-file-style: "linux" - * End: - */