From 57c97d81903576882bf818f15b67ff7abccb739f Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Mon, 25 Apr 2022 20:59:42 +0200 Subject: [PATCH] Fix #224: support for cmdline -- finit.fstab=/etc/fstab.secondary This adds support for bringing up the system with an alternate fstab at boot. E.g., when using a primary/secondary setup for boot partitions. By default /etc/fstab is read, like before, this can now be changed using configure --with-fstab=/path/to/fstab.primary, which sets the default that can be overridden using finit.fstab=/etc/fstab.secondary If mounting, or fsck, fails in any way, Finit calls its own bundled sulogin, or the system sulogin(8), to let the user handle the issue. If there is no sulogin available, Finit will try to start up in its rescue.conf boot mode. Please note, in either of these rescue modes, use `reboot -f` to get the system to reboot. Finit is on pause in the background in rescue mode and cannot be relied on (since there may not be any writable filesystems available.). Signed-off-by: Joachim Wiberg --- Makefile.am | 2 ++ configure.ac | 11 ++++++ doc/cmdline.md | 19 +++++++++++ man/finit.8 | 42 +++++++++++++++++++++++ src/conf.c | 6 ++++ src/finit.c | 93 ++++++++++++++++++++++++++++++++------------------ src/finit.h | 1 + 7 files changed, 140 insertions(+), 34 deletions(-) diff --git a/Makefile.am b/Makefile.am index be039931..f71de8b0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -29,3 +29,5 @@ release: distcheck printf "$$file.md5\t"; cat ../$$file.md5 | cut -f1 -d' '; \ printf "$$file.sha256\t"; cat ../$$file.sha256 | cut -f1 -d' '; \ done + +DISTCHECK_CONFIGURE_FLAGS = --with-fstab=/etc/fstab diff --git a/configure.ac b/configure.ac index abdb1b29..923db532 100644 --- a/configure.ac +++ b/configure.ac @@ -96,6 +96,10 @@ AC_PLUGIN([tty], [yes], [Automatically activate new TTYs, e.g. USB-to- AC_PLUGIN([urandom], [yes], [Setup and save random seed at boot/shutdown]) # Check for extra arguments or packages +AC_ARG_WITH(fstab, + AS_HELP_STRING([--with-fstab=FILE], [System default fstab, default $sysconfdir/fstab]), + [fstab=$withval], [fstab=yes]) + AC_ARG_WITH(heading, AS_HELP_STRING([--with-heading=GREET], [Heading for boot progress. Default: PRETTY_NAME from /etc/os-release, fallback to "Finit vX.YY"]), [heading=$withval], [heading=yes]) @@ -164,6 +168,12 @@ AS_IF([test "x$enable_logrotate" != "xno"], [ AM_CONDITIONAL(LOGROTATE, [test "x$enable_logrotate" = "xyes"]) ### With features ############################################################################## +AS_IF([test "x$with_fstab" != "xno"], [ + AS_IF([test "x$fstab" = "xyes"], [fstab=$sysconfdir/fstab]) + AC_EXPAND_DIR(fstab_path, "$fstab") + AC_DEFINE_UNQUOTED(FINIT_FSTAB, "$fstab_path", [Built-in default: /etc/fstab])],[ + AC_DEFINE_UNQUOTED(FINIT_FSTAB, NULL, [No built-in default fstab])]) + AS_IF([test "x$with_config" != "xno"], [ AS_IF([test "x$conf" = "xyes"], [ conf=$sysconfdir/finit.conf])]) @@ -261,6 +271,7 @@ cat <`: Tell Finit to use an + alternate `fstab` to mount the file system from. Remember, this file + must be on the `root=...` file system provided to Finit from the + kernel. By default the built-in fstab is used, which itself defaults + to `/etc/fstab`, but can be changed at build time with: + + ./configure --with-fstab=/path/to/fstab + + It is even possible to disable a built-in default using: + + ./configure --without-fstab + + Making `finit.fstab=/path/to/fstab` a *mandatory* command line option. + Note, if the command line fstab is missing, Finit falls back to the + built-in fstab, and if both are missing, the system treats this as a + bad `fsck` and thus calls `sulogin`. If, in turn, `sulogin` is not + available on the system, Finit calls reboot, which is also what will + happen when a user exits from `sulogin`. + * `finit.status[=bool]`: Control finit boot progress, including banner. (Used to be `finit.show_status`, which works but is deprecated.) diff --git a/man/finit.8 b/man/finit.8 index f0013ae1..aa3f0c22 100644 --- a/man/finit.8 +++ b/man/finit.8 @@ -13,6 +13,7 @@ .Nm /sbin/finit .Op -- .Op finit.debug +.Op finit.fstab=/etc/fstab.alt .Op finit.status= .Op finit.status_style= .Op rescue | recover @@ -77,6 +78,43 @@ Enable Finit debug messages on system console and log. Sometimes useful when doing board bringup. Before the system log daemon has started, Finit use the kernel ring buffer, .Pa /dev/kmsg . +.It Cm finit.fstab=/path/to/fstab.alt +Tell +.Nm +to use an alternate +.Cm fstab +to mount the file system from. Remember, this file must be on the +.Cm root=... +file system provided to Finit from the kernel. If this file is missing, +.Nm +falls back to its built-in default, which can be changed at build time +using the +.Cm --with-fstab=/path/to/footab +configure option. It is even possible to completely disable the +built-in using +.Cm --without-fstab , +meaning +.Nm +.Sy must +be started with the +.Cm finit.fstab +option. +.Pp +Should +.Nm +discover that there is no fstab file available, including the fallback, +it triggers the same failure mode as when +.Cm fsck +fails, starting +.Xr sulogin 8 , +if that is availble. When +.Cm sulogin +is missing, or when the user exits from +.Cm sulogin , +the system is rebooted. +.Pp +Default fstab, unless changed at build-time: +.Pa /etc/fstab .It Cm finit.status= Control finit boot progress, including banner. This used to be called .Cm finit.show_status , @@ -108,6 +146,10 @@ Before laucnhing services, the system needs to be bootstrapped. This involves mounting all filesystems (not already mounted by an initramfs) in .Pa /etc/fstab , +or any alternate +.Pa fstab +file provided on the Finit command line using +.Cm finit.fstab , ensuring that necessary filesystems like: .Pa /dev , .Pa /proc , diff --git a/src/conf.c b/src/conf.c index 7c19d1c9..eb4740dc 100644 --- a/src/conf.c +++ b/src/conf.c @@ -87,6 +87,7 @@ int get_bool(char *arg, int default_value) /* * finit.debug = [on,off] + * finit.fstab = /path/to/etc/fstab.aternative * finit.status = [on,off] (compat finit.show_status) * finit.status_style = [old,classic,modern] */ @@ -103,6 +104,11 @@ static void parse_finit_opts(char *opt) return; } + if (string_compare(opt, "fstab")) { + fstab = arg; + return; + } + if (string_compare(opt, "status_style")) { if (!arg) { _e("status_style option requires an argument, skipping."); diff --git a/src/finit.c b/src/finit.c index c36cd860..d49a5135 100644 --- a/src/finit.c +++ b/src/finit.c @@ -65,6 +65,7 @@ int rescue = 0; /* rescue mode from kernel cmdline */ int single = 0; /* single user mode from kernel cmdline */ int bootstrap = 1; /* set while bootrapping (for TTYs) */ int kerndebug = 0; /* set if /proc/sys/kernel/printk > 7 */ +char *fstab = FINIT_FSTAB; char *sdown = NULL; char *network = NULL; char *hostname = NULL; @@ -105,6 +106,35 @@ static void banner(void) #endif } +static int sulogin(int do_reboot) +{ + int rc = EX_OSFILE; + char *cmd[] = { + _PATH_SULOGIN, + "sulogin", + }; + size_t i; + + for (i = 0; i < NELEMS(cmd); i++) { + char *path = which(cmd[i]); + + if (access(path, X_OK)) { + free(path); + continue; + } + + rc = systemf("%s", path); + break; + } + + if (do_reboot) { + do_shutdown(SHUT_REBOOT); + exit(rc); + } + + return rc; +} + /* * Check all filesystems in /etc/fstab with a fs_passno > 0 */ @@ -114,10 +144,10 @@ static int fsck(int pass) int rc = 0; FILE *fp; - fp = setmntent("/etc/fstab", "r"); + fp = setmntent(fstab, "r"); if (!fp) { - _pe("Failed opening fstab"); - return 1; + _pe("Failed opening fstab: %s", fstab); + sulogin(1); } while ((mnt = getmntent(fp))) { @@ -153,19 +183,8 @@ static int fsck(int pass) * errors were corrected but that the boot may proceed. */ if (fsck_rc > 1) { - char *sulogin[] = { - _PATH_SULOGIN, - "sulogin", - }; - size_t i; - - for (i = 0; i < NELEMS(sulogin); i++) { - if (systemf("%s", sulogin[i])) - continue; - break; - } - - do_shutdown(SHUT_REBOOT); + logit(LOG_CONSOLE | LOG_ALERT, "Failed fsck of %s, attempting sulogin ...", mnt->mnt_fsname); + sulogin(1); } rc += fsck_rc; } @@ -208,7 +227,7 @@ static void fs_remount_root(int fsckerr) struct mntent *mnt; FILE *fp; - fp = setmntent("/etc/fstab", "r"); + fp = setmntent(fstab, "r"); if (!fp) return; @@ -306,13 +325,29 @@ static void fs_finalize(void) static void fs_mount_all(void) { + char cmd[256] = "mount -na"; + + if (!fstab || !fexist(fstab)) { + logit(LOG_CONSOLE | LOG_NOTICE, "%s system fstab %s, trying fallback ...", + !fstab ? "Missing" : "Cannot find", fstab ?: "\b"); + fstab = FINIT_FSTAB; + } + if (!fstab || !fexist(fstab)) { + logit(LOG_CONSOLE | LOG_EMERG, "%s system fstab %s, attempting sulogin ...", + !fstab ? "Missing" : "Cannot find", fstab ?: "\b"); + sulogin(1); + } + if (!rescue) fs_remount_root(fsck_all()); _d("Root FS up, calling hooks ..."); plugin_run_hooks(HOOK_ROOTFS_UP); - if (run_interactive("mount -na", "Mounting filesystems")) + if (fstab && strcmp(fstab, "/etc/fstab")) + snprintf(cmd, sizeof(cmd), "mount -na -T %s", fstab); + + if (run_interactive(cmd, "Mounting filesystems from %s", fstab)) plugin_run_hooks(HOOK_MOUNT_ERROR); _d("Calling extra mount hook, after mount -a ..."); @@ -595,21 +630,8 @@ int main(int argc, char *argv[]) /* * In case of emergency. */ - if (rescue) { - char *sulogin[] = { - _PATH_SULOGIN, - "sulogin", - }; - size_t i; - - for (i = 0; i < NELEMS(sulogin); i++) { - if (systemf("%s", sulogin[i])) - continue; - - rescue = 0; - break; - } - } + if (rescue) + rescue = sulogin(0); /* * Load plugins early, the first hook is in banner(), so we @@ -638,7 +660,10 @@ int main(int argc, char *argv[]) */ cgroup_init(&loop); - /* Check and mount filesystems. */ + /* + * Check custom fstab from cmdline, including fallback, then run + * fsck before mounting all filesystems, on error call sulogin. + */ fs_mount_all(); /* Bootstrap conditions, needed for hooks */ diff --git a/src/finit.h b/src/finit.h index df165524..4e4c6889 100644 --- a/src/finit.h +++ b/src/finit.h @@ -116,6 +116,7 @@ extern int rescue; extern int single; extern int bootstrap; extern int kerndebug; +extern char *fstab; extern char *sdown; extern char *network; extern char *hostname;