+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
#include "alloc-util.h"
#include "fd-util.h"
+#include "fs-util.h"
#include "fileio.h"
#include "fstab-util.h"
#include "generator.h"
bool noauto,
bool nofail) {
- _cleanup_free_ char *name = NULL, *unit = NULL, *lnk = NULL;
+ _cleanup_free_ char *name = NULL, *unit = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
"Failed to create unit file %s: %m",
unit);
- fputs("# Automatically generated by systemd-fstab-generator\n\n"
- "[Unit]\n"
- "SourcePath=/etc/fstab\n"
- "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
- "[Swap]\n", f);
+ fputs_unlocked("# Automatically generated by systemd-fstab-generator\n\n"
+ "[Unit]\n"
+ "SourcePath=/etc/fstab\n"
+ "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
+ "[Swap]\n", f);
r = write_what(f, what);
if (r < 0)
return r;
if (!noauto) {
- lnk = strjoin(arg_dest, "/" SPECIAL_SWAP_TARGET,
- nofail ? ".wants/" : ".requires/", name, NULL);
- if (!lnk)
- return log_oom();
-
- mkdir_parents_label(lnk, 0755);
- if (symlink(unit, lnk) < 0)
- return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
+ r = generator_add_symlink(arg_dest, SPECIAL_SWAP_TARGET,
+ nofail ? "wants" : "requires", name);
+ if (r < 0)
+ return r;
}
return 0;
}
static int write_timeout(FILE *f, const char *where, const char *opts,
- const char *filter, const char *variable) {
+ const char *filter, const char *variable) {
_cleanup_free_ char *timeout = NULL;
char timespan[FORMAT_TIMESPAN_MAX];
usec_t u;
if (r == 0)
return 0;
- r = parse_sec(timeout, &u);
+ r = parse_sec_fix_0(timeout, &u);
if (r < 0) {
log_warning("Failed to parse timeout for %s, ignoring: %s", where, timeout);
return 0;
const char *dest,
const char *what,
const char *where,
+ const char *original_where,
const char *fstype,
const char *opts,
int passno,
const char *source) {
_cleanup_free_ char
- *name = NULL, *unit = NULL, *lnk = NULL,
+ *name = NULL, *unit = NULL,
*automount_name = NULL, *automount_unit = NULL,
*filtered = NULL;
_cleanup_fclose_ FILE *f = NULL;
"Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
source);
- if (!noauto && !nofail && !automount)
+ if (STRPTR_IN_SET(fstype, "nfs", "nfs4") && !automount &&
+ fstab_test_yes_no_option(opts, "bg\0" "fg\0")) {
+ /* The default retry timeout that mount.nfs uses for 'bg' mounts
+ * is 10000 minutes, where as it uses 2 minutes for 'fg' mounts.
+ * As we are making 'bg' mounts look like an 'fg' mount to
+ * mount.nfs (so systemd can manage the job-control aspects of 'bg'),
+ * we need to explicitly preserve that default, and also ensure
+ * the systemd mount-timeout doesn't interfere.
+ * By placing these options first, they can be over-ridden by
+ * settings in /etc/fstab. */
+ opts = strjoina("x-systemd.mount-timeout=infinity,retry=10000,", opts, ",fg");
+ nofail = true;
+ }
+
+ if (!nofail && !automount)
fprintf(f, "Before=%s\n", post);
if (!automount && opts) {
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)
if (r < 0)
return r;
+ r = generator_write_device_deps(dest, what, where, opts);
+ if (r < 0)
+ return r;
+
r = write_mount_timeout(f, where, opts);
if (r < 0)
return r;
return log_error_errno(r, "Failed to write unit file %s: %m", unit);
if (!noauto && !automount) {
- lnk = strjoin(dest, "/", post, nofail ? ".wants/" : ".requires/", name);
- if (!lnk)
- return log_oom();
-
- mkdir_parents_label(lnk, 0755);
- if (symlink(unit, lnk) < 0)
- return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
+ r = generator_add_symlink(dest, post,
+ nofail ? "wants" : "requires", name);
+ if (r < 0)
+ return r;
}
if (automount) {
if (r < 0)
return log_error_errno(r, "Failed to write unit file %s: %m", automount_unit);
- free(lnk);
- lnk = strjoin(dest, "/", post, nofail ? ".wants/" : ".requires/", automount_name);
- if (!lnk)
- return log_oom();
-
- mkdir_parents_label(lnk, 0755);
- if (symlink(automount_unit, lnk) < 0)
- return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
+ r = generator_add_symlink(dest, post,
+ nofail ? "wants" : "requires", automount_name);
+ if (r < 0)
+ return r;
}
return 0;
}
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;
continue;
}
- where = initrd ? strappend("/sysroot/", me->mnt_dir) : strdup(me->mnt_dir);
+ where = strdup(me->mnt_dir);
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");
k = add_mount(arg_dest,
what,
- where,
+ canonical_where ?: where,
+ canonical_where ? where: NULL,
me->mnt_type,
me->mnt_opts,
me->mnt_passno,
return add_mount(arg_dest,
what,
"/sysroot",
+ NULL,
arg_root_fstype,
opts,
is_device_path(what) ? 1 : 0, /* passno */
return add_mount(arg_dest,
what,
"/sysroot/usr",
+ NULL,
arg_usr_fstype,
opts,
is_device_path(what) ? 1 : 0, /* passno */
return add_mount(arg_dest_late,
"tmpfs",
"/var",
+ NULL,
"tmpfs",
"mode=0755",
0,