systemd/SOURCES/0321-fstab-generator-split-...

409 lines
18 KiB
Diff

From ddcdc462b935fc210677f664d61cf556fb2abe0f Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Mon, 8 May 2023 19:45:34 +0900
Subject: [PATCH] fstab-generator: split out several functions from
parse_fstab()
No functional changes, just refactoring and preparation for later
commits.
(cherry picked from commit cfeb4d378ecd1ea50c0a0248c384e49983511fa8)
Related: #2190226
---
src/fstab-generator/fstab-generator.c | 323 ++++++++++++++------------
1 file changed, 171 insertions(+), 152 deletions(-)
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
index bbd669e477..4ea95f29eb 100644
--- a/src/fstab-generator/fstab-generator.c
+++ b/src/fstab-generator/fstab-generator.c
@@ -99,7 +99,7 @@ static int write_what(FILE *f, const char *what) {
static int add_swap(
const char *source,
const char *what,
- struct mntent *me,
+ const char *options,
MountPointFlags flags) {
_cleanup_free_ char *name = NULL;
@@ -107,7 +107,6 @@ static int add_swap(
int r;
assert(what);
- assert(me);
if (!arg_swap_enabled) {
log_info("Swap unit generation disabled on kernel command line, ignoring fstab swap entry for %s.", what);
@@ -155,7 +154,7 @@ static int add_swap(
if (r < 0)
return r;
- r = write_options(f, me->mnt_opts);
+ r = write_options(f, options);
if (r < 0)
return r;
@@ -164,7 +163,7 @@ static int add_swap(
return log_error_errno(r, "Failed to write unit file %s: %m", name);
/* use what as where, to have a nicer error message */
- r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL);
+ r = generator_write_timeouts(arg_dest, what, what, options, NULL);
if (r < 0)
return r;
@@ -188,18 +187,14 @@ static int add_swap(
return true;
}
-static bool mount_is_network(struct mntent *me) {
- assert(me);
-
- return fstab_test_option(me->mnt_opts, "_netdev\0") ||
- fstype_is_network(me->mnt_type);
+static bool mount_is_network(const char *fstype, const char *options) {
+ return fstab_test_option(options, "_netdev\0") ||
+ (fstype && fstype_is_network(fstype));
}
-static bool mount_in_initrd(struct mntent *me) {
- assert(me);
-
- return fstab_test_option(me->mnt_opts, "x-initrd.mount\0") ||
- path_equal(me->mnt_dir, "/usr");
+static bool mount_in_initrd(const char *where, const char *options) {
+ return fstab_test_option(options, "x-initrd.mount\0") ||
+ (where && path_equal(where, "/usr"));
}
static int write_timeout(
@@ -634,6 +629,20 @@ static const char* sysroot_fstab_path(void) {
return getenv("SYSTEMD_SYSROOT_FSTAB") ?: "/sysroot/etc/fstab";
}
+static bool sysfs_check(void) {
+ static int cached = -1;
+ int r;
+
+ if (cached < 0) {
+ r = getenv_bool_secure("SYSTEMD_SYSFS_CHECK");
+ if (r < 0 && r != -ENXIO)
+ log_debug_errno(r, "Failed to parse $SYSTEMD_SYSFS_CHECK, ignoring: %m");
+ cached = r != 0;
+ }
+
+ return cached;
+}
+
static int add_sysusr_sysroot_usr_bind_mount(const char *source) {
return add_mount(source,
arg_dest,
@@ -647,11 +656,153 @@ static int add_sysusr_sysroot_usr_bind_mount(const char *source) {
SPECIAL_INITRD_FS_TARGET);
}
+static MountPointFlags fstab_options_to_flags(const char *options, bool is_swap) {
+ MountPointFlags flags = 0;
+
+ if (fstab_test_option(options, "x-systemd.makefs\0"))
+ flags |= MOUNT_MAKEFS;
+ if (fstab_test_option(options, "x-systemd.growfs\0"))
+ flags |= MOUNT_GROWFS;
+ if (fstab_test_yes_no_option(options, "noauto\0" "auto\0"))
+ flags |= MOUNT_NOAUTO;
+ if (fstab_test_yes_no_option(options, "nofail\0" "fail\0"))
+ flags |= MOUNT_NOFAIL;
+
+ if (!is_swap) {
+ if (fstab_test_option(options, "x-systemd.rw-only\0"))
+ flags |= MOUNT_RW_ONLY;
+ if (fstab_test_option(options,
+ "comment=systemd.automount\0"
+ "x-systemd.automount\0"))
+ flags |= MOUNT_AUTOMOUNT;
+ }
+
+ return flags;
+}
+
+static int parse_fstab_one(
+ const char *source,
+ const char *what_original,
+ const char *where_original,
+ const char *fstype,
+ const char *options,
+ int passno,
+ bool initrd) {
+
+ _cleanup_free_ char *what = NULL, *where = NULL, *canonical_where = NULL;
+ MountPointFlags flags;
+ int r;
+
+ assert(what_original);
+ assert(where_original);
+ assert(fstype);
+ assert(options);
+
+ if (initrd && !mount_in_initrd(where_original, options))
+ return 0;
+
+ what = fstab_node_to_udev_node(what_original);
+ if (!what)
+ return log_oom();
+
+ if (path_is_read_only_fs("/sys") > 0 &&
+ (streq(what, "sysfs") ||
+ (sysfs_check() && is_device_path(what)))) {
+ log_info("/sys/ is read-only (running in a container?), ignoring mount for %s.", what);
+ return 0;
+ }
+
+ where = strdup(where_original);
+ if (!where)
+ return log_oom();
+
+ if (is_path(where)) {
+ path_simplify(where);
+
+ /* Follow symlinks here; see 5261ba901845c084de5a8fd06500ed09bfb0bd80 which makes sense for
+ * mount units, but causes problems since it historically worked to have symlinks in e.g.
+ * /etc/fstab. So we canonicalize here. Note that we use CHASE_NONEXISTENT to handle the case
+ * where a symlink refers to another mount target; this works assuming the sub-mountpoint
+ * target is the final directory.
+ *
+ * FIXME: when chase() learns to chase non-existent paths, use this here and
+ * drop the prefixing with /sysroot on error below.
+ */
+ r = chase_symlinks(where, initrd ? "/sysroot" : NULL, CHASE_PREFIX_ROOT | CHASE_NONEXISTENT,
+ &canonical_where, NULL);
+ if (r < 0) {
+ /* If we can't canonicalize, continue as if it wasn't a symlink */
+ log_debug_errno(r, "Failed to read symlink target for %s, using as-is: %m", where);
+
+ if (initrd) {
+ canonical_where = path_join("/sysroot", where);
+ if (!canonical_where)
+ return log_oom();
+ }
+
+ } else if (streq(canonical_where, where)) /* If it was fully canonicalized, suppress the change */
+ canonical_where = mfree(canonical_where);
+ else
+ log_debug("Canonicalized what=%s where=%s to %s", what, where, canonical_where);
+ }
+
+ flags = fstab_options_to_flags(options, streq_ptr(fstype, "swap"));
+
+ log_debug("Found entry what=%s where=%s type=%s makefs=%s growfs=%s noauto=%s nofail=%s",
+ what, where, strna(fstype),
+ yes_no(flags & MOUNT_MAKEFS), yes_no(flags & MOUNT_GROWFS),
+ yes_no(flags & MOUNT_NOAUTO), yes_no(flags & MOUNT_NOFAIL));
+
+ if (streq_ptr(fstype, "swap"))
+ return add_swap(source, what, options, flags);
+
+ bool is_sysroot = in_initrd() && path_equal(where, "/sysroot");
+ /* See comment from add_sysroot_usr_mount() about the need for extra indirection in case /usr needs
+ * to be mounted in order for the root fs to be synthesized based on configuration included in /usr/,
+ * e.g. systemd-repart. */
+ bool is_sysroot_usr = in_initrd() && path_equal(where, "/sysroot/usr");
+
+ const char *target_unit =
+ initrd ? SPECIAL_INITRD_FS_TARGET :
+ is_sysroot ? SPECIAL_INITRD_ROOT_FS_TARGET :
+ is_sysroot_usr ? SPECIAL_INITRD_USR_FS_TARGET :
+ mount_is_network(fstype, options) ? SPECIAL_REMOTE_FS_TARGET :
+ SPECIAL_LOCAL_FS_TARGET;
+
+ if (is_sysroot && is_device_path(what)) {
+ r = generator_write_initrd_root_device_deps(arg_dest, what);
+ if (r < 0)
+ return r;
+ }
+
+ r = add_mount(source,
+ arg_dest,
+ what,
+ is_sysroot_usr ? "/sysusr/usr" : canonical_where ?: where,
+ !is_sysroot_usr && canonical_where ? where : NULL,
+ fstype,
+ options,
+ passno,
+ flags,
+ target_unit);
+ if (r <= 0)
+ return r;
+
+ if (is_sysroot_usr) {
+ log_debug("Synthesizing fstab entry what=/sysusr/usr where=/sysroot/usr opts=bind");
+ r = add_sysusr_sysroot_usr_bind_mount(source);
+ if (r < 0)
+ return r;
+ }
+
+ return true;
+}
+
static int parse_fstab(bool initrd) {
_cleanup_endmntent_ FILE *f = NULL;
const char *fstab;
struct mntent *me;
- int r = 0, sysfs_check = -1;
+ int r, ret = 0;
if (initrd)
fstab = sysroot_fstab_path();
@@ -671,146 +822,14 @@ static int parse_fstab(bool initrd) {
}
while ((me = getmntent(f))) {
- _cleanup_free_ char *where = NULL, *what = NULL, *canonical_where = NULL;
- bool makefs, growfs, noauto, nofail;
- MountPointFlags flags;
- int k;
-
- if (initrd && !mount_in_initrd(me))
- continue;
-
- what = fstab_node_to_udev_node(me->mnt_fsname);
- if (!what)
- return log_oom();
-
- if (path_is_read_only_fs("/sys") > 0) {
- if (streq(what, "sysfs")) {
- log_info("Running in a container, ignoring fstab entry for %s.", what);
- continue;
- }
-
- if (sysfs_check < 0) {
- r = getenv_bool_secure("SYSTEMD_SYSFS_CHECK");
- if (r < 0 && r != -ENXIO)
- log_debug_errno(r, "Failed to parse $SYSTEMD_SYSFS_CHECK, ignoring: %m");
- sysfs_check = r != 0;
- }
-
- if (sysfs_check && is_device_path(what)) {
- log_info("/sys/ is read-only (running in a container?), ignoring fstab device entry for %s.", what);
- continue;
- }
- }
-
- where = strdup(me->mnt_dir);
- if (!where)
- return log_oom();
-
- if (is_path(where)) {
- path_simplify(where);
-
- /* Follow symlinks here; see 5261ba901845c084de5a8fd06500ed09bfb0bd80 which makes sense for
- * mount units, but causes problems since it historically worked to have symlinks in e.g.
- * /etc/fstab. So we canonicalize here. Note that we use CHASE_NONEXISTENT to handle the case
- * where a symlink refers to another mount target; this works assuming the sub-mountpoint
- * target is the final directory.
- *
- * FIXME: when chase_symlinks() learns to chase non-existent paths, use this here and
- * drop the prefixing with /sysroot on error below.
- */
- k = chase_symlinks(where, initrd ? "/sysroot" : NULL,
- CHASE_PREFIX_ROOT | CHASE_NONEXISTENT,
- &canonical_where, NULL);
- if (k < 0) {
- /* If we can't canonicalize, continue as if it wasn't a symlink */
- log_debug_errno(k, "Failed to read symlink target for %s, using as-is: %m", where);
-
- if (initrd) {
- canonical_where = path_join("/sysroot", where);
- if (!canonical_where)
- return log_oom();
- }
-
- } else if (streq(canonical_where, where)) /* If it was fully canonicalized, suppress the change */
- canonical_where = mfree(canonical_where);
- else
- log_debug("Canonicalized what=%s where=%s to %s", what, where, canonical_where);
- }
-
- makefs = fstab_test_option(me->mnt_opts, "x-systemd.makefs\0");
- growfs = fstab_test_option(me->mnt_opts, "x-systemd.growfs\0");
- noauto = fstab_test_yes_no_option(me->mnt_opts, "noauto\0" "auto\0");
- nofail = fstab_test_yes_no_option(me->mnt_opts, "nofail\0" "fail\0");
-
- log_debug("Found entry what=%s where=%s type=%s makefs=%s growfs=%s noauto=%s nofail=%s",
- what, where, me->mnt_type,
- yes_no(makefs), yes_no(growfs),
- yes_no(noauto), yes_no(nofail));
-
- flags = makefs * MOUNT_MAKEFS |
- growfs * MOUNT_GROWFS |
- noauto * MOUNT_NOAUTO |
- nofail * MOUNT_NOFAIL;
-
- if (streq(me->mnt_type, "swap"))
- k = add_swap(fstab, what, me, flags);
- else {
- bool rw_only, automount, is_sysroot, is_sysroot_usr;
-
- rw_only = fstab_test_option(me->mnt_opts, "x-systemd.rw-only\0");
- automount = fstab_test_option(me->mnt_opts,
- "comment=systemd.automount\0"
- "x-systemd.automount\0");
-
- flags |= rw_only * MOUNT_RW_ONLY |
- automount * MOUNT_AUTOMOUNT;
-
- is_sysroot = in_initrd() && path_equal(where, "/sysroot");
- /* See comment from add_sysroot_usr_mount about the need for extra indirection
- * in case /usr needs to be mounted in order for the root fs to be synthesized
- * based on configuration included in /usr/, e.g. systemd-repart. */
- is_sysroot_usr = in_initrd() && path_equal(where, "/sysroot/usr");
-
- const char *target_unit =
- initrd ? SPECIAL_INITRD_FS_TARGET :
- is_sysroot ? SPECIAL_INITRD_ROOT_FS_TARGET :
- is_sysroot_usr ? SPECIAL_INITRD_USR_FS_TARGET :
- mount_is_network(me) ? SPECIAL_REMOTE_FS_TARGET :
- SPECIAL_LOCAL_FS_TARGET;
-
- if (is_sysroot && is_device_path(what)) {
- r = generator_write_initrd_root_device_deps(arg_dest, what);
- if (r < 0)
- return r;
- }
-
- k = add_mount(fstab,
- arg_dest,
- what,
- is_sysroot_usr ? "/sysusr/usr" : canonical_where ?: where,
- !is_sysroot_usr && canonical_where ? where : NULL,
- me->mnt_type,
- me->mnt_opts,
- me->mnt_passno,
- flags,
- target_unit);
-
- if (is_sysroot_usr && k >= 0) {
- log_debug("Synthesizing fstab entry what=/sysusr/usr where=/sysroot/usr opts=bind");
-
- r = add_sysusr_sysroot_usr_bind_mount(fstab);
- if (r != 0)
- k = r;
- }
- }
-
- if (arg_sysroot_check && k > 0)
+ r = parse_fstab_one(fstab, me->mnt_fsname, me->mnt_dir, me->mnt_type, me->mnt_opts, me->mnt_passno, initrd);
+ if (r < 0 && ret >= 0)
+ ret = r;
+ if (arg_sysroot_check && r > 0)
return true; /* We found a mount or swap that would be started… */
- if (r >= 0 && k < 0)
- r = k;
}
- return r;
+ return ret;
}
static int sysroot_is_nfsroot(void) {