From e558d5871bc448de02102c648d001f4f3570b34c Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Mon, 12 Oct 2020 13:09:41 +0200 Subject: [PATCH 1/9] Move argument-hiding magic together with argument parsing Everything else Finit does related to parsing the incoming arguments is in conf.c, so it makes sense for this block to also reside there. --- src/conf.c | 18 ++++++++++++++++++ src/finit.c | 13 ------------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/conf.c b/src/conf.c index c15e4b1e..4d9c95dc 100644 --- a/src/conf.c +++ b/src/conf.c @@ -59,6 +59,22 @@ static TAILQ_HEAD(head, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(c static int parse_conf(char *file); static void drop_changes(void); +static void hide_args(int argc, char *argv[]) +{ + /* + * Hide command line arguments from ps (in particular for + * forked children that don't execv()). This is an ugly + * hack that only works on Linux. + * https://web.archive.org/web/20110227041321/http://netsplit.com/2007/01/10/hiding-arguments-from-ps/ + */ + if (argc > 1) { + char *arg_end; + + arg_end = argv[argc-1] + strlen (argv[argc-1]); + *arg_end = ' '; + } +} + static void parse_arg(char *arg, int *dbg) { /* Catches finit_debug (deprecated), --debug, and debug */ @@ -84,6 +100,8 @@ void conf_parse_cmdline(int argc, char *argv[]) for (int i = 1; i < argc; i++) parse_arg(argv[i], &dbg); + hide_args(argc, argv); + fp = fopen("/proc/cmdline", "r"); if (!fp) goto done; diff --git a/src/finit.c b/src/finit.c index 584c5a58..e7e778ea 100644 --- a/src/finit.c +++ b/src/finit.c @@ -298,19 +298,6 @@ int main(int argc, char *argv[]) */ conf_parse_cmdline(argc, argv); - /* - * Hide command line arguments from ps (in particular for - * forked children that don't execv()). This is an ugly - * hack that only works on Linux. - * https://web.archive.org/web/20110227041321/http://netsplit.com/2007/01/10/hiding-arguments-from-ps/ - */ - if (argc > 1) { - char *arg_end; - - arg_end = argv[argc-1] + strlen (argv[argc-1]); - *arg_end = ' '; - } - /* * Initalize event context. */ From 9c8df123e8530e2d0da8de9b7b59c0bf0d2eb6e9 Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Tue, 13 Oct 2020 15:23:41 +0200 Subject: [PATCH 2/9] Always run banner plugin hook Upcoming external plugin support means that even though there are no internal plugins that depend on this hook, there might be external ones. --- src/finit.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/finit.c b/src/finit.c index e7e778ea..5a272a34 100644 --- a/src/finit.c +++ b/src/finit.c @@ -74,10 +74,7 @@ static int udev = 0; /* Runtime detection of udev */ */ static void banner(void) { - if (plugin_exists(HOOK_BANNER)) { - plugin_run_hooks(HOOK_BANNER); - return; - } + plugin_run_hooks(HOOK_BANNER); if (log_is_silent()) return; From b280c8a16aa078b3095f23a42ad0ab4ca892a0f8 Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Tue, 13 Oct 2020 15:26:51 +0200 Subject: [PATCH 3/9] Remove comments from fsck --- src/finit.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/finit.c b/src/finit.c index 5a272a34..db1637f3 100644 --- a/src/finit.c +++ b/src/finit.c @@ -88,7 +88,6 @@ static void banner(void) static int fsck(int pass) { struct fstab *fs; -// int save; int rc = 0; if (!setfsent()) { @@ -96,9 +95,6 @@ static int fsck(int pass) return 1; } -// if ((save = log_is_debug())) -// log_debug(); - while ((fs = getfsent())) { char cmd[80]; struct stat st; @@ -123,8 +119,6 @@ static int fsck(int pass) rc += run_interactive(cmd, "Checking filesystem %.13s", fs->fs_spec); } -// if (save) -// log_debug(); endfsent(); return rc; From 4febd288ef513b943964d692c74d980cfd399fb7 Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Tue, 13 Oct 2020 15:30:15 +0200 Subject: [PATCH 4/9] Defer all filesystem setup to the user via /etc/fstab Traditionally, Finit has setup _some_ filesystems that are Nice To Have (tm), using options that do the Right Thing (tm). On the one hand, this is very convenient for users that don't necessarily know what a reasonable mode= value is for /tmp etc. (pun intended). It also means that mountpoints can be created if they don't exist. On the other hand it means that all users are forced to submit to the choices made by Finit. Also, different filesystems where spread out at many different points in `main()`, meaning that the fact that `/proc` was available at a given hook point did not imply that `/sys` was, for example. Instead, defer _all_ filesystem setup to the user by simply calling `mount -a`. We then ship an example `fstab` that shows how to re-create the old behavior. --- contrib/fstab.bb | 15 ++++ src/finit.c | 198 ++++++++++++++++++++--------------------------- src/plugin.c | 7 +- 3 files changed, 105 insertions(+), 115 deletions(-) create mode 100644 contrib/fstab.bb diff --git a/contrib/fstab.bb b/contrib/fstab.bb new file mode 100644 index 00000000..672bd0f6 --- /dev/null +++ b/contrib/fstab.bb @@ -0,0 +1,15 @@ +# This is a basic /etc/fstab that mounts up all of the virtual filesystems +# that older versions of Finit used to mount internally. It can serve as a +# starting point for systems running Busybox's mount implementation. Make +# sure that CONFIG_FEATURE_MOUNT_HELPERS enabled; as this is required +# create the /dev/{pts,shm} directories. + +devtmpfs /dev devtmpfs defaults 0 0 +mkdir#-p /dev/pts helper none 0 0 +devpts /dev/pts devpts mode=620,ptmxmode=0666 0 0 +mkdir#-p /dev/shm helper none 0 0 +tmpfs /dev/shm tmpfs mode=0777 0 0 +proc /proc proc defaults 0 0 +tmpfs /tmp tmpfs mode=1777,nosuid,nodev 0 0 +tmpfs /run tmpfs mode=0755,nosuid,nodev 0 0 +sysfs /sys sysfs defaults 0 0 diff --git a/src/finit.c b/src/finit.c index db1637f3..423cfb50 100644 --- a/src/finit.c +++ b/src/finit.c @@ -124,6 +124,80 @@ static int fsck(int pass) return rc; } +static int fsck_all(void) +{ + int pass, rc = 0; + + for (pass = 1; pass < 10; pass++) { + rc = fsck(pass); + if (rc) + break; + } + + return rc; +} + +#ifndef SYSROOT +static void fs_remount_root(int fsckerr) +{ + struct fstab *fs; + + if (!setfsent()) + return; + + while ((fs = getfsent())) { + if (!strcmp(fs->fs_file, "/")) + break; + } + + /* If / is not listed in fstab, or listed as 'ro', leave it + * alone. */ + if (!fs || !strcmp(fs->fs_type, "ro")) + goto out; + + if (fsckerr) + print(1, "Cannot remount / as read-write, fsck failed before"); + else + run_interactive("mount -n -o remount,rw /", + "Remounting / as read-write"); + +out: + endfsent(); +} +#else +static void fs_remount_root(int fsckerr) +{ + /* + * XXX: Untested, in the initramfs age we should + * probably use switch_root instead. + */ + rc = mount(SYSROOT, "/", NULL, MS_MOVE, NULL); +} +#endif /* SYSROOT */ + +static void fs_init(void) +{ + int fsckerr; + + if (!rescue) { + fsckerr = fsck_all(); + fs_remount_root(fsckerr); + } + + + _d("Root FS up, calling hooks ..."); + plugin_run_hooks(HOOK_ROOTFS_UP); + + if (run_interactive("mount -na", "Mounting filesystems")) + plugin_run_hooks(HOOK_MOUNT_ERROR); + + _d("Calling extra mount hook, after mount -a ..."); + plugin_run_hooks(HOOK_MOUNT_POST); + + run("swapon -ea"); + umask(0022); +} + /* * If everything goes south we can use this to give the operator an * emergency shell to debug the problem -- Finit should not crash! @@ -274,7 +348,6 @@ int main(int argc, char *argv[]) uev_ctx_t loop; char cmd[256]; char *path; - int rc = 0; /* * finit/init/telinit client tool uses /dev/initctl pipe @@ -314,17 +387,14 @@ int main(int argc, char *argv[]) emergency_shell(); /* - * Initial setup of signals, ignore all until we're up. + * Hello world. */ - sig_init(); + banner(); /* - * Mount base file system + * Initial setup of signals, ignore all until we're up. */ - if (!fismnt("/proc") && mount("none", "/proc", "proc", 0, NULL)) - _pe("Failed mounting /proc"); - if (fisdir("/proc/bus/usb")) - mount("none", "/proc/bus/usb", "usbfs", 0, NULL); + sig_init(); /* * Load plugins early, finit.conf may contain references to @@ -332,67 +402,6 @@ int main(int argc, char *argv[]) */ plugin_init(&loop); - /* - * Hello world. - */ - banner(); - - /* - * Check file systems listed with pass > 0 in /etc/fstab - */ - rc = 0; - for (int pass = 1; pass < 10 && !rescue; pass++) { - rc = fsck(pass); - if (rc) - break; - } - - /* - * Mount filesystems - */ - if (!rescue) { -#ifndef SYSROOT - /* - * Remount / read-write if it exists in fstab is not 'ro'. - * This is what the Debian sysv initscripts does. - */ - if (setfsent()) { - struct fstab *fs; - - while ((fs = getfsent())) { - if (strcmp(fs->fs_file, "/")) - continue; - - if (strcmp(fs->fs_type, "ro")) { - if (rc) - print(1, "Cannot remount / as read-write, fsck failed before"); - else - rc = run_interactive("mount -n -o remount,rw /", "Remounting / as read-write"); - } - break; - } - - endfsent(); - } -#else - /* - * XXX: Untested, in the initramfs age we should - * probably use switch_root instead. - */ - rc = mount(SYSROOT, "/", NULL, MS_MOVE, NULL); -#endif - } - - /* Create /sys if missing, some systems don't include it in their rootfs skeleton */ - if (!rc && !fisdir("/sys")) - mkdir("/sys", 0755); - - /* Only mount /sys if it's not already mounted */ - if (!fismnt("/sys") && mount("none", "/sys", "sysfs", 0, NULL)) { - print(1, "Cannot mount /sys, your system may behave unusually"); - _pe("Failed mounting /sys"); - } - /* * Initialize default control groups, if available */ @@ -404,40 +413,16 @@ int main(int argc, char *argv[]) */ conf_init(); - /* - * Some non-embedded systems without an initramfs may not have /dev mounted yet - * If they do, check if system has udevadm and perform cleanup from initramfs - */ - if (!fismnt("/dev")) - mount("udev", "/dev", "devtmpfs", MS_RELATIME, "size=10%,nr_inodes=61156,mode=755"); - else if (whichp("udevadm")) - run_interactive("udevadm info --cleanup-db", "Cleaning up udev db"); - - /* Modern systems use /dev/pts */ - makedir("/dev/pts", 0755); - mount("devpts", "/dev/pts", "devpts", 0, "gid=5,mode=620,ptmxmode=0666"); - - /* - * Some systems rely on us to both create /dev/shm and, to mount - * a tmpfs there. Any system with dbus needs shared memory, so - * mount it, unless its already mounted, but not if listed in - * the /etc/fstab file already. - */ - makedir("/dev/shm", 0755); - if (!fismnt("/dev/shm") && !ismnt("/etc/fstab", "/dev/shm", NULL)) - mount("shm", "/dev/shm", "tmpfs", 0, "mode=0777"); - - /* - * New tmpfs based /run for volatile runtime data - * For details, see http://lwn.net/Articles/436012/ - */ - if (fisdir("/run") && !fismnt("/run")) - mount("tmpfs", "/run", "tmpfs", MS_NODEV | MS_NOSUID | MS_NOEXEC, "mode=0755,size=10%"); - umask(022); + fs_init(); /* Bootstrap conditions, needed for hooks */ cond_init(); + /* Emit conditions for early hooks that ran before the + * condition system was initialized in case anyone . */ + cond_set_oneshot(plugin_hook_str(HOOK_BANNER)); + cond_set_oneshot(plugin_hook_str(HOOK_ROOTFS_UP)); + /* * Populate /dev and prepare for runtime events from kernel. * Prefer udev if mdev is also available on the system. @@ -488,21 +473,6 @@ int main(int argc, char *argv[]) wdog = svc_find(FINIT_LIBPATH_ "/watchdogd", NULL); } - if (!rescue) { - _d("Root FS up, calling hooks ..."); - plugin_run_hooks(HOOK_ROOTFS_UP); - - umask(0); - if (run_interactive("mount -na", "Mounting filesystems")) - plugin_run_hooks(HOOK_MOUNT_ERROR); - - _d("Calling extra mount hook, after mount -a ..."); - plugin_run_hooks(HOOK_MOUNT_POST); - - run("swapon -ea"); - umask(0022); - } - /* Base FS up, enable standard SysV init signals */ sig_setup(&loop); diff --git a/src/plugin.c b/src/plugin.c index 85285b3a..e5bc019e 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -201,7 +201,12 @@ void plugin_run_hook(hook_point_t no, void *arg) } } - cond_set_oneshot(hook_cond[no]); + /* Conditions are stored in /run, so don't try to signal + * conditions for any hooks before filesystems have been + * mounted. */ + if (no >= HOOK_MOUNT_ERROR) + cond_set_oneshot(hook_cond[no]); + service_step_all(SVC_TYPE_RUNTASK); } From 18ab7d31834982b583d088d2b0bbe732f63bf776 Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Tue, 13 Oct 2020 15:47:16 +0200 Subject: [PATCH 5/9] Remove hard-coded hotplug and watchdog daemons Instead of heuristically trying to determine the correct hotplug daemon to use (mdev/udev), defer to the user to specify it in the configuration. Same goes for the built-in watchdog. --- src/finit.c | 61 +---------------------------------------------------- 1 file changed, 1 insertion(+), 60 deletions(-) diff --git a/src/finit.c b/src/finit.c index 423cfb50..7f281d46 100644 --- a/src/finit.c +++ b/src/finit.c @@ -66,8 +66,6 @@ char *runparts = NULL; uev_ctx_t *ctx = NULL; /* Main loop context */ svc_t *wdog = NULL; /* No watchdog by default */ -static int udev = 0; /* Runtime detection of udev */ - /* * Show user configured banner before service bootstrap progress @@ -304,10 +302,6 @@ static void crank_worker(void *unused) */ sm_init(&sm); sm_step(&sm); - - /* Debian has this little script to copy generated rules while the system was read-only */ - if (udev && fexist("/lib/udev/udev-finish")) - run_interactive("/lib/udev/udev-finish", "Finalizing udev"); } /* @@ -346,8 +340,6 @@ int main(int argc, char *argv[]) .delay = 1000 }; uev_ctx_t loop; - char cmd[256]; - char *path; /* * finit/init/telinit client tool uses /dev/initctl pipe @@ -408,8 +400,7 @@ int main(int argc, char *argv[]) cgroup_init(); /* - * Initialize .conf system and load static /etc/finit.conf - * Also initializes global_rlimit[] for udevd, below. + * Initialize .conf system and load static /etc/finit.conf. */ conf_init(); @@ -423,56 +414,6 @@ int main(int argc, char *argv[]) cond_set_oneshot(plugin_hook_str(HOOK_BANNER)); cond_set_oneshot(plugin_hook_str(HOOK_ROOTFS_UP)); - /* - * Populate /dev and prepare for runtime events from kernel. - * Prefer udev if mdev is also available on the system. - */ - path = which("udevd"); - if (!path) - path = which("/lib/systemd/systemd-udevd"); - if (path) { - /* Desktop and server distros usually have a variant of udev */ - udev = 1; - - /* Register udevd as a monitored service */ - snprintf(cmd, sizeof(cmd), "[S12345789] pid:udevd %s -- Device event managing daemon", path); - if (service_register(SVC_TYPE_SERVICE, cmd, global_rlimit, NULL)) { - _pe("Failed registering %s", path); - udev = 0; - } else { - snprintf(cmd, sizeof(cmd), ":1 [S] " - "udevadm trigger -c add -t devices " - "-- Requesting device events", path); - service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL); - - snprintf(cmd, sizeof(cmd), ":2 [S] " - "udevadm trigger -c add -t subsystems " - "-- Requesting subsystem events", path); - service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL); - } - free(path); - } else { - path = which("mdev"); - if (path) { - /* Embedded Linux systems usually have BusyBox mdev */ - if (log_is_debug()) - touch("/dev/mdev.log"); - - snprintf(cmd, sizeof(cmd), "%s -s", path); - free(path); - - run_interactive(cmd, "Populating device tree"); - } - } - - /* - * Start bundled watchdogd as soon as possible, if enabled - */ - if (which(FINIT_LIBPATH_ "/watchdogd")) { - service_register(SVC_TYPE_SERVICE, FINIT_LIBPATH_ "/watchdogd -- Finit watchdog daemon", global_rlimit, NULL); - wdog = svc_find(FINIT_LIBPATH_ "/watchdogd", NULL); - } - /* Base FS up, enable standard SysV init signals */ sig_setup(&loop); From cc655609e2f2d92b4f271f5b37869e383560124b Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Tue, 13 Oct 2020 15:57:30 +0200 Subject: [PATCH 6/9] Do not exempt basefs up hook in rescue mode No other hook is treated in this fashion, so it seems silly to single out poor HOOK_BASEFS_UP. --- src/finit.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/finit.c b/src/finit.c index 7f281d46..cb6a460d 100644 --- a/src/finit.c +++ b/src/finit.c @@ -417,10 +417,8 @@ int main(int argc, char *argv[]) /* Base FS up, enable standard SysV init signals */ sig_setup(&loop); - if (!rescue) { - _d("Base FS up, calling hooks ..."); - plugin_run_hooks(HOOK_BASEFS_UP); - } + _d("Base FS up, calling hooks ..."); + plugin_run_hooks(HOOK_BASEFS_UP); /* * Set up inotify watcher for /etc/finit.d and read all .conf From 100cea5d9fad01b7f456d8e317086089a30aa238 Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Tue, 20 Oct 2020 09:07:32 +0200 Subject: [PATCH 7/9] Read configuration after filesystem mount The contents of /etc/finit.conf and friends could potentially change after mounting /etc/fstab. If, for example, /etc was to be re-mounted from ro to rw using an overlay filesystem, we want any user changes to the configuration to take effect. --- src/finit.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/finit.c b/src/finit.c index cb6a460d..46492e4e 100644 --- a/src/finit.c +++ b/src/finit.c @@ -399,13 +399,15 @@ int main(int argc, char *argv[]) */ cgroup_init(); + + /* Check and mount filesystems. */ + fs_init(); + /* * Initialize .conf system and load static /etc/finit.conf. */ conf_init(); - fs_init(); - /* Bootstrap conditions, needed for hooks */ cond_init(); From bdceeb83d5a22f115c753ce81b58b27787b5cc1e Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Tue, 20 Oct 2020 09:47:37 +0200 Subject: [PATCH 8/9] Ensure that plugins are loaded before the first hook point We want plugins to be able to register themselves at the banner hook point, but that requires that we have actually loaded them before then. --- src/finit.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/finit.c b/src/finit.c index 46492e4e..13c04cda 100644 --- a/src/finit.c +++ b/src/finit.c @@ -378,6 +378,10 @@ int main(int argc, char *argv[]) */ emergency_shell(); + /* Load plugins early, the first hook is in banner(), so we + * need plugins loaded before calling it. */ + plugin_init(&loop); + /* * Hello world. */ @@ -388,12 +392,6 @@ int main(int argc, char *argv[]) */ sig_init(); - /* - * Load plugins early, finit.conf may contain references to - * features implemented by plugins. - */ - plugin_init(&loop); - /* * Initialize default control groups, if available */ From adcc78039e005f3b45ec65fa0f4a14b1a1eed306 Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Tue, 20 Oct 2020 14:57:10 +0200 Subject: [PATCH 9/9] Bring back the hotplug-daemon-heuristic as a plugin This way, the default behavior stays the same, but users can opt out by disabling the plugin. --- configure.ac | 1 + doc/plugins.md | 3 ++ plugins/Makefile.am | 8 ++++ plugins/hotplug.c | 110 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 122 insertions(+) create mode 100644 plugins/hotplug.c diff --git a/configure.ac b/configure.ac index 88d8dfbc..465f75d9 100644 --- a/configure.ac +++ b/configure.ac @@ -101,6 +101,7 @@ AC_ARG_ENABLE(contrib, enable_all_plugins=auto AC_PLUGIN([alsa-utils], [no], [Save and restore ALSA sound settings using alsactl]) AC_PLUGIN([dbus], [no], [Setup and start system message bus, D-Bus]) +AC_PLUGIN([hotplug], [yes], [Setup and start udev or mdev hotplug daemon]) AC_PLUGIN([inetd-echo], [no], [Inetd plugin: echo server, RFC862]) AC_PLUGIN([inetd-chargen], [no], [Inetd plugin: character generator, RFC864]) AC_PLUGIN([inetd-daytime], [no], [Inetd plugin: daytime server, RFC867]) diff --git a/doc/plugins.md b/doc/plugins.md index bdc96b4d..6a546a6a 100644 --- a/doc/plugins.md +++ b/doc/plugins.md @@ -42,6 +42,9 @@ For your convenience a set of *optional* plugins are available: * *discard.so*: RFC 863 plugin. Start as inetd service, like time below. +* *hotplug.so*: Setup and start either udev or mdev hotplug daemon, if + available. + * *rtc.so*: Restore and save system clock from/to RTC on boot/halt. * *initctl.so*: Extends finit with a traditional `initctl` functionality. diff --git a/plugins/Makefile.am b/plugins/Makefile.am index c26acf01..cb0022ee 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -17,6 +17,10 @@ if BUILD_DBUS_PLUGIN libplug_la_SOURCES += dbus.c endif +if BUILD_HOTPLUG_PLUGIN +libplug_la_SOURCES += hotplug.c +endif + if INETD if BUILD_INETD_ECHO_PLUGIN libplug_la_SOURCES += echo.c @@ -62,6 +66,10 @@ if BUILD_DBUS_PLUGIN pkglib_LTLIBRARIES += dbus.la endif +if BUILD_HOTPLUG_PLUGIN +pkglib_LTLIBRARIES += hotplug.la +endif + if INETD if BUILD_INETD_ECHO_PLUGIN pkglib_LTLIBRARIES += echo.la diff --git a/plugins/hotplug.c b/plugins/hotplug.c new file mode 100644 index 00000000..5ec91f67 --- /dev/null +++ b/plugins/hotplug.c @@ -0,0 +1,110 @@ +/* Heuristically find and initialize a suitable hotplug daemon + * + * Copyright (c) 2012-2020 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 + +#include "config.h" +#include "conf.h" +#include "finit.h" +#include "helpers.h" +#include "plugin.h" +#include "service.h" + +static void setup(void *arg) +{ + char cmd[256]; + char *path; + + /* + * Populate /dev and prepare for runtime events from kernel. + * Prefer udev if mdev is also available on the system. + */ + path = which("udevd"); + if (!path) + path = which("/lib/systemd/systemd-udevd"); + if (path) { + /* Register udevd as a monitored service */ + snprintf(cmd, sizeof(cmd), "[S12345789] pid:udevd %s " + "-- Device event managing daemon", path); + if (service_register(SVC_TYPE_SERVICE, cmd, global_rlimit, NULL)) { + _pe("Failed registering %s", path); + } else { + snprintf(cmd, sizeof(cmd), ":1 [S] " + "udevadm trigger -c add -t devices " + "-- Requesting device events", path); + service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL); + + snprintf(cmd, sizeof(cmd), ":2 [S] " + "udevadm trigger -c add -t subsystems " + "-- Requesting subsystem events", path); + service_register(SVC_TYPE_RUN, cmd, global_rlimit, NULL); + } + + free(path); + + /* Debian has this little script to copy generated + * rules while the system was read-only. TODO: When + * this functionality was hardcoded in finit.c, this + * call was made in crank_worker(). Now that + * filesystems are mounted earlier we should be able + * to make this call directly after the triggers have + * run, but this has not been tested AT ALL. */ + if (fexist("/lib/udev/udev-finish")) + run_interactive("/lib/udev/udev-finish", "Finalizing udev"); + } else { + path = which("mdev"); + if (path) { + /* Embedded Linux systems usually have BusyBox mdev */ + if (log_is_debug()) + touch("/dev/mdev.log"); + + snprintf(cmd, sizeof(cmd), "%s -s", path); + free(path); + + run_interactive(cmd, "Populating device tree"); + } + } +} + +static plugin_t plugin = { + .name = __FILE__, + .hook[HOOK_BASEFS_UP] = { + .cb = setup + }, +}; + +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: + */