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,