diff --git a/man/systemd-fstab-generator.xml b/man/systemd-fstab-generator.xml index 50d24d67f0..b898d719f2 100644 --- a/man/systemd-fstab-generator.xml +++ b/man/systemd-fstab-generator.xml @@ -71,6 +71,14 @@ for more information about special /etc/fstab mount options this generator understands. + One special topic is handling of symbolic links. Historical init + implementations supported symlinks in /etc/fstab. + Because mount units will refuse mounts where the target is a symbolic link, + this generator will resolve any symlinks as far as possible when processing + /etc/fstab in order to enhance backwards compatibility. + If a symlink target does not exist at the time that this generator runs, it + is assumed that the symlink target is the final target of the mount. + systemd-fstab-generator implements systemd.generator7. diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml index 98f71d2e7e..1bed7d17f1 100644 --- a/man/systemd.mount.xml +++ b/man/systemd.mount.xml @@ -373,8 +373,9 @@ Where= - Takes an absolute path of a directory of the - mount point. If the mount point does not exist at the time of + Takes an absolute path of a directory for the + mount point; in particular, the destination cannot be a symbolic + link. If the mount point does not exist at the time of mounting, it is created. This string must be reflected in the unit filename. (See above.) This option is mandatory. diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index ce9dccfe68..7f23b9fd74 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -25,6 +25,7 @@ #include "alloc-util.h" #include "fd-util.h" +#include "fs-util.h" #include "fileio.h" #include "fstab-util.h" #include "generator.h" @@ -290,6 +291,7 @@ static int add_mount( const char *dest, const char *what, const char *where, + const char *original_where, const char *fstype, const char *opts, int passno, @@ -396,11 +398,10 @@ static int add_mount( return r; } - fprintf(f, - "\n" - "[Mount]\n" - "Where=%s\n", - where); + fprintf(f, "\n[Mount]\n"); + if (original_where) + fprintf(f, "# Canonicalized from %s\n", original_where); + fprintf(f, "Where=%s\n", where); r = write_what(f, what); if (r < 0) @@ -520,7 +521,7 @@ static int parse_fstab(bool initrd) { } while ((me = getmntent(f))) { - _cleanup_free_ char *where = NULL, *what = NULL; + _cleanup_free_ char *where = NULL, *what = NULL, *canonical_where = NULL; bool noauto, nofail; int k; @@ -540,8 +541,28 @@ static int parse_fstab(bool initrd) { if (!where) return log_oom(); - if (is_path(where)) + if (is_path(where)) { path_kill_slashes(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. + */ + r = chase_symlinks(where, initrd ? "/sysroot" : NULL, + CHASE_PREFIX_ROOT | CHASE_NONEXISTENT, + &canonical_where); + if (r < 0) + /* In this case for now we continue on as if it wasn't a symlink */ + log_warning_errno(r, "Failed to read symlink target for %s: %m", where); + else { + if (streq(canonical_where, where)) + canonical_where = mfree(canonical_where); + else + log_debug("Canonicalized what=%s where=%s to %s", + what, where, canonical_where); + } + } 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"); @@ -567,7 +588,8 @@ static int parse_fstab(bool initrd) { k = add_mount(arg_dest, what, - where, + canonical_where ?: where, + canonical_where ? where: NULL, me->mnt_type, me->mnt_opts, me->mnt_passno, @@ -630,6 +652,7 @@ static int add_sysroot_mount(void) { return add_mount(arg_dest, what, "/sysroot", + NULL, arg_root_fstype, opts, is_device_path(what) ? 1 : 0, /* passno */ @@ -684,6 +707,7 @@ static int add_sysroot_usr_mount(void) { return add_mount(arg_dest, what, "/sysroot/usr", + NULL, arg_usr_fstype, opts, is_device_path(what) ? 1 : 0, /* passno */ @@ -724,6 +748,7 @@ static int add_volatile_var(void) { return add_mount(arg_dest_late, "tmpfs", "/var", + NULL, "tmpfs", "mode=0755", 0,