]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
fstab-generator: split out several functions from parse_fstab()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 8 May 2023 10:45:34 +0000 (19:45 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 23 May 2023 23:23:22 +0000 (08:23 +0900)
No functional changes, just refactoring and preparation for later
commits.

src/fstab-generator/fstab-generator.c

index 0a5e9cf692ace2ae4fc75f760310465a6d7a9d51..149bd5daf6934e97b18df962d688cee52b46c7a4 100644 (file)
@@ -102,7 +102,7 @@ static int write_what(FILE *f, const char *what) {
 static int add_swap(
                 const char *source,
                 const char *what,
-                struct mntent *me,
+                const char *options,
                 MountPointFlags flags) {
 
         _cleanup_free_ char *name = NULL;
@@ -110,7 +110,6 @@ static int add_swap(
         int r;
 
         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);
@@ -158,7 +157,7 @@ static int add_swap(
         if (r < 0)
                 return r;
 
-        r = write_options(f, me->mnt_opts);
+        r = write_options(f, options);
         if (r < 0)
                 return r;
 
@@ -167,7 +166,7 @@ static int add_swap(
                 return log_error_errno(r, "Failed to write unit file %s: %m", name);
 
         /* use what as where, to have a nicer error message */
-        r = generator_write_timeouts(arg_dest, what, what, me->mnt_opts, NULL);
+        r = generator_write_timeouts(arg_dest, what, what, options, NULL);
         if (r < 0)
                 return r;
 
@@ -193,18 +192,14 @@ static int add_swap(
         return true;
 }
 
-static bool mount_is_network(struct mntent *me) {
-        assert(me);
-
-        return fstab_test_option(me->mnt_opts, "_netdev\0") ||
-               fstype_is_network(me->mnt_type);
+static bool mount_is_network(const char *fstype, const char *options) {
+        return fstab_test_option(options, "_netdev\0") ||
+                (fstype && fstype_is_network(fstype));
 }
 
-static bool mount_in_initrd(struct mntent *me) {
-        assert(me);
-
-        return fstab_test_option(me->mnt_opts, "x-initrd.mount\0") ||
-               path_equal(me->mnt_dir, "/usr");
+static bool mount_in_initrd(const char *where, const char *options) {
+        return fstab_test_option(options, "x-initrd.mount\0") ||
+                (where && path_equal(where, "/usr"));
 }
 
 static int write_timeout(
@@ -643,6 +638,20 @@ static const char* sysroot_fstab_path(void) {
         return getenv("SYSTEMD_SYSROOT_FSTAB") ?: "/sysroot/etc/fstab";
 }
 
+static bool sysfs_check(void) {
+        static int cached = -1;
+        int r;
+
+        if (cached < 0) {
+                r = getenv_bool_secure("SYSTEMD_SYSFS_CHECK");
+                if (r < 0 && r != -ENXIO)
+                        log_debug_errno(r, "Failed to parse $SYSTEMD_SYSFS_CHECK, ignoring: %m");
+                cached = r != 0;
+        }
+
+        return cached;
+}
+
 static int add_sysusr_sysroot_usr_bind_mount(const char *source) {
         return add_mount(source,
                         arg_dest,
@@ -656,11 +665,155 @@ static int add_sysusr_sysroot_usr_bind_mount(const char *source) {
                         SPECIAL_INITRD_FS_TARGET);
 }
 
+static MountPointFlags fstab_options_to_flags(const char *options, bool is_swap) {
+        MountPointFlags flags = 0;
+
+        if (fstab_test_option(options, "x-systemd.makefs\0"))
+                flags |= MOUNT_MAKEFS;
+        if (fstab_test_option(options, "x-systemd.growfs\0"))
+                flags |= MOUNT_GROWFS;
+        if (fstab_test_option(options, "x-systemd.pcrfs\0"))
+                flags |= MOUNT_PCRFS;
+        if (fstab_test_yes_no_option(options, "noauto\0" "auto\0"))
+                flags |= MOUNT_NOAUTO;
+        if (fstab_test_yes_no_option(options, "nofail\0" "fail\0"))
+                flags |= MOUNT_NOFAIL;
+
+        if (!is_swap) {
+                if (fstab_test_option(options, "x-systemd.rw-only\0"))
+                        flags |= MOUNT_RW_ONLY;
+                if (fstab_test_option(options,
+                                      "comment=systemd.automount\0"
+                                      "x-systemd.automount\0"))
+                        flags |= MOUNT_AUTOMOUNT;
+        }
+
+        return flags;
+}
+
+static int parse_fstab_one(
+                const char *source,
+                const char *what_original,
+                const char *where_original,
+                const char *fstype,
+                const char *options,
+                int passno,
+                bool initrd) {
+
+        _cleanup_free_ char *what = NULL, *where = NULL, *canonical_where = NULL;
+        MountPointFlags flags;
+        int r;
+
+        assert(what_original);
+        assert(where_original);
+        assert(fstype);
+        assert(options);
+
+        if (initrd && !mount_in_initrd(where_original, options))
+                return 0;
+
+        what = fstab_node_to_udev_node(what_original);
+        if (!what)
+                return log_oom();
+
+        if (path_is_read_only_fs("/sys") > 0 &&
+            (streq(what, "sysfs") ||
+             (sysfs_check() && is_device_path(what)))) {
+                log_info("/sys/ is read-only (running in a container?), ignoring mount for %s.", what);
+                return 0;
+        }
+
+        where = strdup(where_original);
+        if (!where)
+                return log_oom();
+
+        if (is_path(where)) {
+                path_simplify(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.
+                 *
+                 * FIXME: when chase() learns to chase non-existent paths, use this here and
+                 *        drop the prefixing with /sysroot on error below.
+                 */
+                r = chase(where, initrd ? "/sysroot" : NULL, CHASE_PREFIX_ROOT | CHASE_NONEXISTENT,
+                          &canonical_where, NULL);
+                if (r < 0) {
+                        /* If we can't canonicalize, continue as if it wasn't a symlink */
+                        log_debug_errno(r, "Failed to read symlink target for %s, using as-is: %m", where);
+
+                        if (initrd) {
+                                canonical_where = path_join("/sysroot", where);
+                                if (!canonical_where)
+                                        return log_oom();
+                        }
+
+                } else if (streq(canonical_where, where)) /* If it was fully canonicalized, suppress the change */
+                        canonical_where = mfree(canonical_where);
+                else
+                        log_debug("Canonicalized what=%s where=%s to %s", what, where, canonical_where);
+        }
+
+        flags = fstab_options_to_flags(options, streq_ptr(fstype, "swap"));
+
+        log_debug("Found entry what=%s where=%s type=%s makefs=%s growfs=%s pcrfs=%s noauto=%s nofail=%s",
+                  what, where, strna(fstype),
+                  yes_no(flags & MOUNT_MAKEFS), yes_no(flags & MOUNT_GROWFS), yes_no(flags & MOUNT_PCRFS),
+                  yes_no(flags & MOUNT_NOAUTO), yes_no(flags & MOUNT_NOFAIL));
+
+        if (streq_ptr(fstype, "swap"))
+                return add_swap(source, what, options, flags);
+
+        bool is_sysroot = in_initrd() && path_equal(where, "/sysroot");
+        /* See comment from add_sysroot_usr_mount() about the need for extra indirection in case /usr needs
+         * to be mounted in order for the root fs to be synthesized based on configuration included in /usr/,
+         * e.g. systemd-repart. */
+        bool is_sysroot_usr = in_initrd() && path_equal(where, "/sysroot/usr");
+
+        const char *target_unit =
+                        initrd ?                            SPECIAL_INITRD_FS_TARGET :
+                        is_sysroot ?                        SPECIAL_INITRD_ROOT_FS_TARGET :
+                        is_sysroot_usr ?                    SPECIAL_INITRD_USR_FS_TARGET :
+                        mount_is_network(fstype, options) ? SPECIAL_REMOTE_FS_TARGET :
+                                                            SPECIAL_LOCAL_FS_TARGET;
+
+        if (is_sysroot && is_device_path(what)) {
+                r = generator_write_initrd_root_device_deps(arg_dest, what);
+                if (r < 0)
+                        return r;
+        }
+
+        r = add_mount(source,
+                      arg_dest,
+                      what,
+                      is_sysroot_usr ? "/sysusr/usr" : canonical_where ?: where,
+                      !is_sysroot_usr && canonical_where ? where : NULL,
+                      fstype,
+                      options,
+                      passno,
+                      flags,
+                      target_unit);
+        if (r <= 0)
+                return r;
+
+        if (is_sysroot_usr) {
+                log_debug("Synthesizing fstab entry what=/sysusr/usr where=/sysroot/usr opts=bind");
+                r = add_sysusr_sysroot_usr_bind_mount(source);
+                if (r < 0)
+                        return r;
+        }
+
+        return true;
+}
+
 static int parse_fstab(bool initrd) {
         _cleanup_endmntent_ FILE *f = NULL;
         const char *fstab;
         struct mntent *me;
-        int r = 0, sysfs_check = -1;
+        int r, ret = 0;
 
         if (initrd)
                 fstab = sysroot_fstab_path();
@@ -680,147 +833,14 @@ static int parse_fstab(bool initrd) {
         }
 
         while ((me = getmntent(f))) {
-                _cleanup_free_ char *where = NULL, *what = NULL, *canonical_where = NULL;
-                bool makefs, growfs, pcrfs, noauto, nofail;
-                MountPointFlags flags;
-                int k;
-
-                if (initrd && !mount_in_initrd(me))
-                        continue;
-
-                what = fstab_node_to_udev_node(me->mnt_fsname);
-                if (!what)
-                        return log_oom();
-
-                if (path_is_read_only_fs("/sys") > 0) {
-                        if (streq(what, "sysfs")) {
-                                log_info("/sys/ is read-only (running in a container?), ignoring fstab entry for %s.", me->mnt_dir);
-                                continue;
-                        }
-
-                        if (sysfs_check < 0) {
-                                k = getenv_bool_secure("SYSTEMD_SYSFS_CHECK");
-                                if (k < 0 && k != -ENXIO)
-                                        log_debug_errno(k, "Failed to parse $SYSTEMD_SYSFS_CHECK, ignoring: %m");
-                                sysfs_check = k != 0;
-                        }
-
-                        if (sysfs_check && is_device_path(what)) {
-                                log_info("/sys/ is read-only (running in a container?), ignoring fstab device entry for %s.", what);
-                                continue;
-                        }
-                }
-
-                where = strdup(me->mnt_dir);
-                if (!where)
-                        return log_oom();
-
-                if (is_path(where)) {
-                        path_simplify(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.
-                         *
-                         * FIXME: when chase() learns to chase non-existent paths, use this here and
-                         *        drop the prefixing with /sysroot on error below.
-                         */
-                        k = chase(where, initrd ? "/sysroot" : NULL, CHASE_PREFIX_ROOT | CHASE_NONEXISTENT,
-                                  &canonical_where, NULL);
-                        if (k < 0) {
-                                /* If we can't canonicalize, continue as if it wasn't a symlink */
-                                log_debug_errno(k, "Failed to read symlink target for %s, using as-is: %m", where);
-
-                                if (initrd) {
-                                        canonical_where = path_join("/sysroot", where);
-                                        if (!canonical_where)
-                                                return log_oom();
-                                }
-
-                        } else if (streq(canonical_where, where)) /* If it was fully canonicalized, suppress the change */
-                                canonical_where = mfree(canonical_where);
-                        else
-                                log_debug("Canonicalized what=%s where=%s to %s", what, where, canonical_where);
-                }
-
-                makefs = fstab_test_option(me->mnt_opts, "x-systemd.makefs\0");
-                growfs = fstab_test_option(me->mnt_opts, "x-systemd.growfs\0");
-                pcrfs = fstab_test_option(me->mnt_opts, "x-systemd.pcrfs\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");
-
-                log_debug("Found entry what=%s where=%s type=%s makefs=%s growfs=%s pcrfs=%s noauto=%s nofail=%s",
-                          what, where, me->mnt_type,
-                          yes_no(makefs), yes_no(growfs), yes_no(pcrfs),
-                          yes_no(noauto), yes_no(nofail));
-
-                flags = makefs * MOUNT_MAKEFS |
-                        growfs * MOUNT_GROWFS |
-                        pcrfs * MOUNT_PCRFS |
-                        noauto * MOUNT_NOAUTO |
-                        nofail * MOUNT_NOFAIL;
-
-                if (streq(me->mnt_type, "swap"))
-                        k = add_swap(fstab, what, me, flags);
-                else {
-                        bool rw_only, automount, is_sysroot, is_sysroot_usr;
-
-                        rw_only = fstab_test_option(me->mnt_opts, "x-systemd.rw-only\0");
-                        automount = fstab_test_option(me->mnt_opts,
-                                                      "comment=systemd.automount\0"
-                                                      "x-systemd.automount\0");
-
-                        flags |= rw_only * MOUNT_RW_ONLY |
-                                 automount * MOUNT_AUTOMOUNT;
-
-                        is_sysroot = in_initrd() && path_equal(where, "/sysroot");
-                        /* See comment from add_sysroot_usr_mount about the need for extra indirection
-                         * in case /usr needs to be mounted in order for the root fs to be synthesized
-                         * based on configuration included in /usr/, e.g. systemd-repart. */
-                        is_sysroot_usr = in_initrd() && path_equal(where, "/sysroot/usr");
-
-                        const char *target_unit =
-                                initrd ?               SPECIAL_INITRD_FS_TARGET :
-                                is_sysroot ?           SPECIAL_INITRD_ROOT_FS_TARGET :
-                                is_sysroot_usr ?       SPECIAL_INITRD_USR_FS_TARGET :
-                                mount_is_network(me) ? SPECIAL_REMOTE_FS_TARGET :
-                                                       SPECIAL_LOCAL_FS_TARGET;
-
-                        if (is_sysroot && is_device_path(what)) {
-                                r = generator_write_initrd_root_device_deps(arg_dest, what);
-                                if (r < 0)
-                                        return r;
-                        }
-
-                        k = add_mount(fstab,
-                                      arg_dest,
-                                      what,
-                                      is_sysroot_usr ? "/sysusr/usr" : canonical_where ?: where,
-                                      !is_sysroot_usr && canonical_where ? where : NULL,
-                                      me->mnt_type,
-                                      me->mnt_opts,
-                                      me->mnt_passno,
-                                      flags,
-                                      target_unit);
-
-                        if (is_sysroot_usr && k >= 0) {
-                                log_debug("Synthesizing fstab entry what=/sysusr/usr where=/sysroot/usr opts=bind");
-
-                                r = add_sysusr_sysroot_usr_bind_mount(fstab);
-                                if (r != 0)
-                                        k = r;
-                        }
-                }
-
-                if (arg_sysroot_check && k > 0)
+                r = parse_fstab_one(fstab, me->mnt_fsname, me->mnt_dir, me->mnt_type, me->mnt_opts, me->mnt_passno, initrd);
+                if (r < 0 && ret >= 0)
+                        ret = r;
+                if (arg_sysroot_check && r > 0)
                         return true;  /* We found a mount or swap that would be started… */
-                if (r >= 0 && k < 0)
-                        r = k;
         }
 
-        return r;
+        return ret;
 }
 
 static int sysroot_is_nfsroot(void) {