You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
409 lines
18 KiB
409 lines
18 KiB
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) {
|