Skip to content

Commit

Permalink
Fix #224: support for cmdline -- finit.fstab=/etc/fstab.secondary
Browse files Browse the repository at this point in the history
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 <troglobit@gmail.com>
  • Loading branch information
troglobit committed Apr 25, 2022
1 parent b0d0ca7 commit 57c97d8
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 34 deletions.
2 changes: 2 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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
11 changes: 11 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down Expand Up @@ -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])])
Expand Down Expand Up @@ -261,6 +271,7 @@ cat <<EOF
Exec prefix...........: $eprefix
Sysconfdir............: `eval echo $sysconfdir`
Localstatedir.........: `eval echo $localstatedir`
Default fstab.........: `eval echo $fstab`
Finit config file.....: $conf_path
Finit config.d path...: $rcsd_path
Finit plugin path.....: $plugin_path
Expand Down
19 changes: 19 additions & 0 deletions doc/cmdline.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,25 @@ The `bool` setting is one of `on, off, true false, 1, 0`.
* `finit.debug[=bool]`: Enable finit debug. This is operated
independently of the kernel `debug` setting. New as of Finit v4.

* `finit.fstab=</path/to/etc/fstab.alternative>`: 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.)

Expand Down
42 changes: 42 additions & 0 deletions man/finit.8
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
.Nm /sbin/finit
.Op --
.Op finit.debug
.Op finit.fstab=/etc/fstab.alt
.Op finit.status=<on,off>
.Op finit.status_style=<classic,modern>
.Op rescue | recover
Expand Down Expand Up @@ -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=<on,off>
Control finit boot progress, including banner. This used to be called
.Cm finit.show_status ,
Expand Down Expand Up @@ -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 ,
Expand Down
6 changes: 6 additions & 0 deletions src/conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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]
*/
Expand All @@ -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.");
Expand Down
93 changes: 59 additions & 34 deletions src/finit.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
*/
Expand All @@ -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))) {
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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 ...");
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 */
Expand Down
1 change: 1 addition & 0 deletions src/finit.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 57c97d8

Please sign in to comment.