Skip to content

Commit b5fd395

Browse files
committed
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
1 parent 35df78c commit b5fd395

File tree

1 file changed

+53
-27
lines changed

1 file changed

+53
-27
lines changed

src/fstab-generator/fstab-generator.c

Lines changed: 53 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,40 @@ static MountPointFlags fstab_options_to_flags(const char *options, bool is_swap)
801801
return flags;
802802
}
803803

804+
static int canonicalize_mount_path(const char *path, const char *type, bool initrd, char **ret) {
805+
_cleanup_free_ char *p = NULL;
806+
bool changed;
807+
int r;
808+
809+
assert(path);
810+
assert(type);
811+
assert(STR_IN_SET(type, "where", "what"));
812+
assert(ret);
813+
814+
// FIXME: when chase() learns to chase non-existent paths, use this here and drop the prefixing with
815+
// /sysroot on error below.
816+
r = chase(path, initrd ? "/sysroot" : NULL, CHASE_PREFIX_ROOT | CHASE_NONEXISTENT, &p, NULL);
817+
if (r < 0) {
818+
log_debug_errno(r, "Failed to chase '%s', using as-is: %m", path);
819+
820+
if (initrd)
821+
p = path_join("/sysroot", path);
822+
else
823+
p = strdup(path);
824+
if (!p)
825+
return log_oom();
826+
827+
path_simplify(p);
828+
}
829+
830+
changed = !streq(path, p);
831+
if (changed)
832+
log_debug("Canonicalized %s=%s to %s", type, path, p);
833+
834+
*ret = TAKE_PTR(p);
835+
return changed;
836+
}
837+
804838
static int parse_fstab_one(
805839
const char *source,
806840
const char *what_original,
@@ -813,7 +847,7 @@ static int parse_fstab_one(
813847

814848
_cleanup_free_ char *what = NULL, *where = NULL;
815849
MountPointFlags flags;
816-
bool is_swap;
850+
bool is_swap, where_changed;
817851
int r;
818852

819853
assert(what_original);
@@ -848,49 +882,41 @@ static int parse_fstab_one(
848882
assert(where_original); /* 'where' is not necessary for swap entry. */
849883

850884
if (!is_path(where_original)) {
851-
log_warning("Mount point %s is not a valid path, ignoring.", where);
885+
log_warning("Mount point %s is not a valid path, ignoring.", where_original);
852886
return 0;
853887
}
854888

855889
/* Follow symlinks here; see 5261ba901845c084de5a8fd06500ed09bfb0bd80 which makes sense for
856890
* mount units, but causes problems since it historically worked to have symlinks in e.g.
857891
* /etc/fstab. So we canonicalize here. Note that we use CHASE_NONEXISTENT to handle the case
858892
* where a symlink refers to another mount target; this works assuming the sub-mountpoint
859-
* target is the final directory.
860-
*
861-
* FIXME: when chase() learns to chase non-existent paths, use this here and
862-
* drop the prefixing with /sysroot on error below.
863-
*/
864-
r = chase(where_original, initrd ? "/sysroot" : NULL, CHASE_PREFIX_ROOT | CHASE_NONEXISTENT, &where, NULL);
865-
if (r < 0) {
866-
/* If we can't canonicalize, continue as if it wasn't a symlink */
867-
log_debug_errno(r, "Failed to read symlink target for %s, using as-is: %m", where_original);
893+
* target is the final directory. */
894+
r = canonicalize_mount_path(where_original, "where", initrd, &where);
895+
if (r < 0)
896+
return r;
897+
where_changed = r > 0;
868898

869-
if (initrd)
870-
where = path_join("/sysroot", where_original);
871-
else
872-
where = strdup(where_original);
873-
if (!where)
874-
return log_oom();
899+
if (initrd && fstab_is_bind(options, fstype)) {
900+
/* When in initrd, the source of bind mount needs to be prepended with /sysroot as well. */
901+
_cleanup_free_ char *p = NULL;
875902

876-
path_simplify(where);
877-
}
903+
r = canonicalize_mount_path(what, "what", initrd, &p);
904+
if (r < 0)
905+
return r;
878906

879-
if (streq(where, where_original)) /* If it was fully canonicalized, suppress the change */
880-
where = mfree(where);
881-
else
882-
log_debug("Canonicalized what=%s where=%s to %s", what, where_original, where);
907+
free_and_replace(what, p);
908+
}
883909

884910
log_debug("Found entry what=%s where=%s type=%s makefs=%s growfs=%s pcrfs=%s noauto=%s nofail=%s",
885911
what, where, strna(fstype),
886912
yes_no(flags & MOUNT_MAKEFS), yes_no(flags & MOUNT_GROWFS), yes_no(flags & MOUNT_PCRFS),
887913
yes_no(flags & MOUNT_NOAUTO), yes_no(flags & MOUNT_NOFAIL));
888914

889-
bool is_sysroot = in_initrd() && path_equal(where ?: where_original, "/sysroot");
915+
bool is_sysroot = in_initrd() && path_equal(where, "/sysroot");
890916
/* See comment from add_sysroot_usr_mount() about the need for extra indirection in case /usr needs
891917
* to be mounted in order for the root fs to be synthesized based on configuration included in /usr/,
892918
* e.g. systemd-repart. */
893-
bool is_sysroot_usr = in_initrd() && path_equal(where ?: where_original, "/sysroot/usr");
919+
bool is_sysroot_usr = in_initrd() && path_equal(where, "/sysroot/usr");
894920

895921
const char *target_unit =
896922
initrd ? SPECIAL_INITRD_FS_TARGET :
@@ -902,8 +928,8 @@ static int parse_fstab_one(
902928
r = add_mount(source,
903929
arg_dest,
904930
what,
905-
is_sysroot_usr ? "/sysusr/usr" : where ?: where_original,
906-
!is_sysroot_usr && where ? where_original : NULL,
931+
is_sysroot_usr ? "/sysusr/usr" : where,
932+
!is_sysroot_usr && where_changed ? where_original : NULL,
907933
fstype,
908934
options,
909935
passno,

0 commit comments

Comments
 (0)