]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/fstab-generator/fstab-generator.c
fstab-generator: add x-systemd.rw-only option support
[thirdparty/systemd.git] / src / fstab-generator / fstab-generator.c
index 30a6d356d0e32d24c94c1b52123efc9094c318a0..a8e7c1c1caa4603ce21c07ab0e952f37a965a06b 100644 (file)
@@ -1,11 +1,8 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <errno.h>
-#include <mntent.h>
 #include <stdio.h>
-#include <string.h>
 #include <unistd.h>
-#include <stdio_ext.h>
 
 #include "alloc-util.h"
 #include "fd-util.h"
@@ -38,11 +35,13 @@ typedef enum MountpointFlags {
         AUTOMOUNT = 1 << 2,
         MAKEFS    = 1 << 3,
         GROWFS    = 1 << 4,
+        RWONLY    = 1 << 5,
 } MountpointFlags;
 
 static const char *arg_dest = NULL;
 static const char *arg_dest_late = NULL;
 static bool arg_fstab_enabled = true;
+static bool arg_swap_enabled = true;
 static char *arg_root_what = NULL;
 static char *arg_root_fstype = NULL;
 static char *arg_root_options = NULL;
@@ -101,6 +100,11 @@ static int add_swap(
         assert(what);
         assert(me);
 
+        if (!arg_swap_enabled) {
+                log_info("Swap unit generation disabled on kernel command line, ignoring fstab swap entry for %s.", what);
+                return 0;
+        }
+
         if (access("/proc/swaps", F_OK) < 0) {
                 log_info("Swap not supported, ignoring fstab swap entry for %s.", what);
                 return 0;
@@ -115,15 +119,23 @@ static int add_swap(
         if (r < 0)
                 return log_error_errno(r, "Failed to generate unit name: %m");
 
-        r = generator_open_unit_file(arg_dest, "/etc/fstab", name, &f);
+        r = generator_open_unit_file(arg_dest, fstab_path(), name, &f);
+        if (r < 0)
+                return r;
+
+        fprintf(f,
+                "[Unit]\n"
+                "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n"
+                "SourcePath=%s\n",
+                fstab_path());
+
+        r = generator_write_blockdev_dependency(f, what);
         if (r < 0)
                 return r;
 
-        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);
+        fprintf(f,
+                "\n"
+                "[Swap]\n");
 
         r = write_what(f, what);
         if (r < 0)
@@ -176,8 +188,13 @@ static bool mount_in_initrd(struct mntent *me) {
                streq(me->mnt_dir, "/usr");
 }
 
-static int write_timeout(FILE *f, const char *where, const char *opts,
-                         const char *filter, const char *variable) {
+static int write_timeout(
+                FILE *f,
+                const char *where,
+                const char *opts,
+                const char *filter,
+                const char *variable) {
+
         _cleanup_free_ char *timeout = NULL;
         char timespan[FORMAT_TIMESPAN_MAX];
         usec_t u;
@@ -210,8 +227,12 @@ static int write_mount_timeout(FILE *f, const char *where, const char *opts) {
                              "x-systemd.mount-timeout\0", "TimeoutSec");
 }
 
-static int write_dependency(FILE *f, const char *opts,
-                const char *filter, const char *format) {
+static int write_dependency(
+                FILE *f,
+                const char *opts,
+                const char *filter,
+                const char *format) {
+
         _cleanup_strv_free_ char **names = NULL, **units = NULL;
         _cleanup_free_ char *res = NULL;
         char **s;
@@ -229,9 +250,10 @@ static int write_dependency(FILE *f, const char *opts,
         STRV_FOREACH(s, names) {
                 char *x;
 
-                r = unit_name_mangle_with_suffix(*s, 0, ".mount", &x);
+                r = unit_name_mangle_with_suffix(*s, "as dependency", 0, ".mount", &x);
                 if (r < 0)
                         return log_error_errno(r, "Failed to generate unit name: %m");
+
                 r = strv_consume(&units, x);
                 if (r < 0)
                         return log_oom();
@@ -251,7 +273,8 @@ static int write_dependency(FILE *f, const char *opts,
 }
 
 static int write_after(FILE *f, const char *opts) {
-        return write_dependency(f, opts, "x-systemd.after", "After=%1$s\n");
+        return write_dependency(f, opts,
+                                "x-systemd.after", "After=%1$s\n");
 }
 
 static int write_requires_after(FILE *f, const char *opts) {
@@ -308,6 +331,7 @@ static int add_mount(
                 *automount_name = NULL,
                 *filtered = NULL,
                 *where_escaped = NULL;
+        _cleanup_strv_free_ char **wanted_by = NULL, **required_by = NULL;
         _cleanup_fclose_ FILE *f = NULL;
         int r;
 
@@ -329,6 +353,14 @@ static int add_mount(
             mount_point_ignore(where))
                 return 0;
 
+        r = fstab_extract_values(opts, "x-systemd.wanted-by", &wanted_by);
+        if (r < 0)
+                return r;
+
+        r = fstab_extract_values(opts, "x-systemd.required-by", &required_by);
+        if (r < 0)
+                return r;
+
         if (path_equal(where, "/")) {
                 if (flags & NOAUTO)
                         log_warning("Ignoring \"noauto\" for root device");
@@ -336,7 +368,13 @@ static int add_mount(
                         log_warning("Ignoring \"nofail\" for root device");
                 if (flags & AUTOMOUNT)
                         log_warning("Ignoring automount option for root device");
+                if (!strv_isempty(wanted_by))
+                        log_warning("Ignoring \"x-systemd.wanted-by=\" for root device");
+                if (!strv_isempty(required_by))
+                        log_warning("Ignoring \"x-systemd.required-by=\" for root device");
 
+                required_by = strv_free(required_by);
+                wanted_by = strv_free(wanted_by);
                 SET_FLAG(flags, NOAUTO | NOFAIL | AUTOMOUNT, false);
         }
 
@@ -344,16 +382,22 @@ static int add_mount(
         if (r < 0)
                 return log_error_errno(r, "Failed to generate unit name: %m");
 
-        r = generator_open_unit_file(dest, "/etc/fstab", name, &f);
+        r = generator_open_unit_file(dest, fstab_path(), name, &f);
         if (r < 0)
                 return r;
 
         fprintf(f,
                 "[Unit]\n"
-                "SourcePath=%s\n"
-                "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
+                "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n"
+                "SourcePath=%s\n",
                 source);
 
+        /* All mounts under /sysroot need to happen later, at initrd-fs.target time. IOW, it's not
+         * technically part of the basic initrd filesystem itself, and so shouldn't inherit the default
+         * Before=local-fs.target dependency. */
+        if (in_initrd() && path_startswith(where, "/sysroot"))
+                fprintf(f, "DefaultDependencies=no\n");
+
         if (STRPTR_IN_SET(fstype, "nfs", "nfs4") && !(flags & AUTOMOUNT) &&
             fstab_test_yes_no_option(opts, "bg\0" "fg\0")) {
                 /* The default retry timeout that mount.nfs uses for 'bg' mounts
@@ -392,7 +436,14 @@ static int add_mount(
                         return r;
         }
 
-        fprintf(f, "\n[Mount]\n");
+        r = generator_write_blockdev_dependency(f, what);
+        if (r < 0)
+                return r;
+
+        fprintf(f,
+                "\n"
+                "[Mount]\n");
+
         if (original_where)
                 fprintf(f, "# Canonicalized from %s\n", original_where);
 
@@ -431,6 +482,9 @@ static int add_mount(
         if (r < 0)
                 return r;
 
+        if (flags & RWONLY)
+                fprintf(f, "ReadWriteOnly=yes\n");
+
         r = fflush_and_check(f);
         if (r < 0)
                 return log_error_errno(r, "Failed to write unit file %s: %m", name);
@@ -447,21 +501,35 @@ static int add_mount(
                         return r;
         }
 
-        if (!(flags & NOAUTO) && !(flags & AUTOMOUNT)) {
-                r = generator_add_symlink(dest, post,
-                                          (flags & NOFAIL) ? "wants" : "requires", name);
-                if (r < 0)
-                        return r;
-        }
-
-        if (flags & AUTOMOUNT) {
+        if (!FLAGS_SET(flags, AUTOMOUNT)) {
+                if (!FLAGS_SET(flags, NOAUTO) && strv_isempty(wanted_by) && strv_isempty(required_by)) {
+                        r = generator_add_symlink(dest, post,
+                                                  (flags & NOFAIL) ? "wants" : "requires", name);
+                        if (r < 0)
+                                return r;
+                } else {
+                        char **s;
+
+                        STRV_FOREACH(s, wanted_by) {
+                                r = generator_add_symlink(dest, *s, "wants", name);
+                                if (r < 0)
+                                        return r;
+                        }
+
+                        STRV_FOREACH(s, required_by) {
+                                r = generator_add_symlink(dest, *s, "requires", name);
+                                if (r < 0)
+                                        return r;
+                        }
+                }
+        } else {
                 r = unit_name_from_path(where, ".automount", &automount_name);
                 if (r < 0)
                         return log_error_errno(r, "Failed to generate unit name: %m");
 
-                fclose(f);
+                f = safe_fclose(f);
 
-                r = generator_open_unit_file(dest, "/etc/fstab", automount_name, &f);
+                r = generator_open_unit_file(dest, fstab_path(), automount_name, &f);
                 if (r < 0)
                         return r;
 
@@ -513,24 +581,24 @@ static int add_mount(
 
 static int parse_fstab(bool initrd) {
         _cleanup_endmntent_ FILE *f = NULL;
-        const char *fstab_path;
+        const char *fstab;
         struct mntent *me;
         int r = 0;
 
-        fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
-        log_debug("Parsing %s...", fstab_path);
+        fstab = initrd ? "/sysroot/etc/fstab" : fstab_path();
+        log_debug("Parsing %s...", fstab);
 
-        f = setmntent(fstab_path, "re");
+        f = setmntent(fstab, "re");
         if (!f) {
                 if (errno == ENOENT)
                         return 0;
 
-                return log_error_errno(errno, "Failed to open %s: %m", fstab_path);
+                return log_error_errno(errno, "Failed to open %s: %m", fstab);
         }
 
         while ((me = getmntent(f))) {
                 _cleanup_free_ char *where = NULL, *what = NULL, *canonical_where = NULL;
-                bool makefs, growfs, noauto, nofail;
+                bool makefs, growfs, noauto, nofail, rwonly;
                 int k;
 
                 if (initrd && !mount_in_initrd(me))
@@ -559,7 +627,7 @@ static int parse_fstab(bool initrd) {
                          * target is the final directory. */
                         r = chase_symlinks(where, initrd ? "/sysroot" : NULL,
                                            CHASE_PREFIX_ROOT | CHASE_NONEXISTENT,
-                                           &canonical_where);
+                                           &canonical_where, NULL);
                         if (r < 0) /* If we can't canonicalize we continue on as if it wasn't a symlink */
                                 log_debug_errno(r, "Failed to read symlink target for %s, ignoring: %m", where);
                         else if (streq(canonical_where, where)) /* If it was fully canonicalized, suppress the change */
@@ -570,6 +638,7 @@ static int parse_fstab(bool initrd) {
 
                 makefs = fstab_test_option(me->mnt_opts, "x-systemd.makefs\0");
                 growfs = fstab_test_option(me->mnt_opts, "x-systemd.growfs\0");
+                rwonly = fstab_test_option(me->mnt_opts, "x-systemd.rw-only\0");
                 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");
 
@@ -602,9 +671,9 @@ static int parse_fstab(bool initrd) {
                                       me->mnt_type,
                                       me->mnt_opts,
                                       me->mnt_passno,
-                                      makefs*MAKEFS | growfs*GROWFS | noauto*NOAUTO | nofail*NOFAIL | automount*AUTOMOUNT,
+                                      makefs*MAKEFS | growfs*GROWFS | noauto*NOAUTO | nofail*NOFAIL | automount*AUTOMOUNT | rwonly*RWONLY,
                                       post,
-                                      fstab_path);
+                                      fstab);
                 }
 
                 if (r >= 0 && k < 0)
@@ -722,10 +791,11 @@ static int add_sysroot_usr_mount(void) {
 }
 
 static int add_volatile_root(void) {
+
         /* Let's add in systemd-remount-volatile.service which will remount the root device to tmpfs if this is
-         * requested, leaving only /usr from the root mount inside. */
+         * requested (or as an overlayfs), leaving only /usr from the root mount inside. */
 
-        if (arg_volatile_mode != VOLATILE_YES)
+        if (!IN_SET(arg_volatile_mode, VOLATILE_YES, VOLATILE_OVERLAY))
                 return 0;
 
         return generator_add_symlink(arg_dest, SPECIAL_INITRD_ROOT_FS_TARGET, "requires",
@@ -837,6 +907,14 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
                                 arg_volatile_mode = m;
                 } else
                         arg_volatile_mode = VOLATILE_YES;
+
+        } else if (streq(key, "systemd.swap")) {
+
+                r = value ? parse_boolean(value) : 1;
+                if (r < 0)
+                        log_warning("Failed to parse systemd.swap switch %s. Ignoring.", value);
+                else
+                        arg_swap_enabled = r;
         }
 
         return 0;