151 lines
6.3 KiB
Diff
151 lines
6.3 KiB
Diff
From e47358d080fb705b4aa89f8506c4bf0e0fce6910 Mon Sep 17 00:00:00 2001
|
|
From: Mike Yuan <me@yhndnzj.com>
|
|
Date: Thu, 13 Jul 2023 22:44:19 +0800
|
|
Subject: [PATCH] fstab-generator: resolve bind mount source when in initrd
|
|
|
|
We currently prepend /sysroot to mount points for entries
|
|
in /sysroot/etc/fstab. But when it comes to bind mounts,
|
|
the source needs to canonicalized too.
|
|
|
|
Fixes #6827
|
|
Replaces #7894
|
|
|
|
(cherry picked from commit b5fd3956ecaff8ef5f0b1826076965cab5fce604)
|
|
|
|
Related: #2190226
|
|
---
|
|
src/fstab-generator/fstab-generator.c | 79 ++++++++++++++++++---------
|
|
1 file changed, 53 insertions(+), 26 deletions(-)
|
|
|
|
diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c
|
|
index 6756885478..4885d6d722 100644
|
|
--- a/src/fstab-generator/fstab-generator.c
|
|
+++ b/src/fstab-generator/fstab-generator.c
|
|
@@ -793,6 +793,40 @@ static MountPointFlags fstab_options_to_flags(const char *options, bool is_swap)
|
|
return flags;
|
|
}
|
|
|
|
+static int canonicalize_mount_path(const char *path, const char *type, bool initrd, char **ret) {
|
|
+ _cleanup_free_ char *p = NULL;
|
|
+ bool changed;
|
|
+ int r;
|
|
+
|
|
+ assert(path);
|
|
+ assert(type);
|
|
+ assert(STR_IN_SET(type, "where", "what"));
|
|
+ assert(ret);
|
|
+
|
|
+ // FIXME: when chase() learns to chase non-existent paths, use this here and drop the prefixing with
|
|
+ // /sysroot on error below.
|
|
+ r = chase_symlinks(path, initrd ? "/sysroot" : NULL, CHASE_PREFIX_ROOT | CHASE_NONEXISTENT, &p, NULL);
|
|
+ if (r < 0) {
|
|
+ log_debug_errno(r, "Failed to chase '%s', using as-is: %m", path);
|
|
+
|
|
+ if (initrd)
|
|
+ p = path_join("/sysroot", path);
|
|
+ else
|
|
+ p = strdup(path);
|
|
+ if (!p)
|
|
+ return log_oom();
|
|
+
|
|
+ path_simplify(p);
|
|
+ }
|
|
+
|
|
+ changed = !streq(path, p);
|
|
+ if (changed)
|
|
+ log_debug("Canonicalized %s=%s to %s", type, path, p);
|
|
+
|
|
+ *ret = TAKE_PTR(p);
|
|
+ return changed;
|
|
+}
|
|
+
|
|
static int parse_fstab_one(
|
|
const char *source,
|
|
const char *what_original,
|
|
@@ -805,7 +839,7 @@ static int parse_fstab_one(
|
|
|
|
_cleanup_free_ char *what = NULL, *where = NULL;
|
|
MountPointFlags flags;
|
|
- bool is_swap;
|
|
+ bool is_swap, where_changed;
|
|
int r;
|
|
|
|
assert(what_original);
|
|
@@ -840,7 +874,7 @@ static int parse_fstab_one(
|
|
assert(where_original); /* 'where' is not necessary for swap entry. */
|
|
|
|
if (!is_path(where_original)) {
|
|
- log_warning("Mount point %s is not a valid path, ignoring.", where);
|
|
+ log_warning("Mount point %s is not a valid path, ignoring.", where_original);
|
|
return 0;
|
|
}
|
|
|
|
@@ -848,41 +882,34 @@ static int parse_fstab_one(
|
|
* 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_original, initrd ? "/sysroot" : NULL, CHASE_PREFIX_ROOT | CHASE_NONEXISTENT, &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_original);
|
|
+ * target is the final directory. */
|
|
+ r = canonicalize_mount_path(where_original, "where", initrd, &where);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
+ where_changed = r > 0;
|
|
|
|
- if (initrd)
|
|
- where = path_join("/sysroot", where_original);
|
|
- else
|
|
- where = strdup(where_original);
|
|
- if (!where)
|
|
- return log_oom();
|
|
+ if (initrd && fstab_is_bind(options, fstype)) {
|
|
+ /* When in initrd, the source of bind mount needs to be prepended with /sysroot as well. */
|
|
+ _cleanup_free_ char *p = NULL;
|
|
+
|
|
+ r = canonicalize_mount_path(what, "what", initrd, &p);
|
|
+ if (r < 0)
|
|
+ return r;
|
|
|
|
- path_simplify(where);
|
|
+ free_and_replace(what, p);
|
|
}
|
|
|
|
- if (streq(where, where_original)) /* If it was fully canonicalized, suppress the change */
|
|
- where = mfree(where);
|
|
- else
|
|
- log_debug("Canonicalized what=%s where=%s to %s", what, where_original, where);
|
|
|
|
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));
|
|
|
|
- bool is_sysroot = in_initrd() && path_equal(where ?: where_original, "/sysroot");
|
|
+ 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 ?: where_original, "/sysroot/usr");
|
|
+ bool is_sysroot_usr = in_initrd() && path_equal(where, "/sysroot/usr");
|
|
|
|
const char *target_unit =
|
|
initrd ? SPECIAL_INITRD_FS_TARGET :
|
|
@@ -894,8 +921,8 @@ static int parse_fstab_one(
|
|
r = add_mount(source,
|
|
arg_dest,
|
|
what,
|
|
- is_sysroot_usr ? "/sysusr/usr" : where ?: where_original,
|
|
- !is_sysroot_usr && where ? where_original : NULL,
|
|
+ is_sysroot_usr ? "/sysusr/usr" : where,
|
|
+ !is_sysroot_usr && where_changed ? where_original : NULL,
|
|
fstype,
|
|
options,
|
|
passno,
|