1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 #include "alloc-util.h"
11 #include "fstab-util.h"
12 #include "generator.h"
14 #include "main-func.h"
16 #include "mount-setup.h"
17 #include "mount-util.h"
18 #include "mountpoint-util.h"
19 #include "parse-util.h"
20 #include "path-util.h"
21 #include "proc-cmdline.h"
23 #include "specifier.h"
24 #include "stat-util.h"
25 #include "string-util.h"
27 #include "unit-name.h"
30 #include "volatile-util.h"
32 typedef enum MountPointFlags
{
33 MOUNT_NOAUTO
= 1 << 0,
34 MOUNT_NOFAIL
= 1 << 1,
35 MOUNT_AUTOMOUNT
= 1 << 2,
36 MOUNT_MAKEFS
= 1 << 3,
37 MOUNT_GROWFS
= 1 << 4,
38 MOUNT_RW_ONLY
= 1 << 5,
41 static const char *arg_dest
= NULL
;
42 static const char *arg_dest_late
= NULL
;
43 static bool arg_fstab_enabled
= true;
44 static bool arg_swap_enabled
= true;
45 static char *arg_root_what
= NULL
;
46 static char *arg_root_fstype
= NULL
;
47 static char *arg_root_options
= NULL
;
48 static char *arg_root_hash
= NULL
;
49 static int arg_root_rw
= -1;
50 static char *arg_usr_what
= NULL
;
51 static char *arg_usr_fstype
= NULL
;
52 static char *arg_usr_options
= NULL
;
53 static VolatileMode arg_volatile_mode
= _VOLATILE_MODE_INVALID
;
55 STATIC_DESTRUCTOR_REGISTER(arg_root_what
, freep
);
56 STATIC_DESTRUCTOR_REGISTER(arg_root_fstype
, freep
);
57 STATIC_DESTRUCTOR_REGISTER(arg_root_options
, freep
);
58 STATIC_DESTRUCTOR_REGISTER(arg_root_hash
, freep
);
59 STATIC_DESTRUCTOR_REGISTER(arg_usr_what
, freep
);
60 STATIC_DESTRUCTOR_REGISTER(arg_usr_fstype
, freep
);
61 STATIC_DESTRUCTOR_REGISTER(arg_usr_options
, freep
);
63 static int write_options(FILE *f
, const char *options
) {
64 _cleanup_free_
char *o
= NULL
;
69 if (streq(options
, "defaults"))
72 o
= specifier_escape(options
);
76 fprintf(f
, "Options=%s\n", o
);
80 static int write_what(FILE *f
, const char *what
) {
81 _cleanup_free_
char *w
= NULL
;
83 w
= specifier_escape(what
);
87 fprintf(f
, "What=%s\n", w
);
94 MountPointFlags flags
) {
96 _cleanup_free_
char *name
= NULL
;
97 _cleanup_fclose_
FILE *f
= NULL
;
103 if (!arg_swap_enabled
) {
104 log_info("Swap unit generation disabled on kernel command line, ignoring fstab swap entry for %s.", what
);
108 if (access("/proc/swaps", F_OK
) < 0) {
109 log_info("Swap not supported, ignoring fstab swap entry for %s.", what
);
113 if (detect_container() > 0) {
114 log_info("Running in a container, ignoring fstab swap entry for %s.", what
);
118 r
= unit_name_from_path(what
, ".swap", &name
);
120 return log_error_errno(r
, "Failed to generate unit name: %m");
122 r
= generator_open_unit_file(arg_dest
, fstab_path(), name
, &f
);
128 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n"
132 r
= generator_write_blockdev_dependency(f
, what
);
140 r
= write_what(f
, what
);
144 r
= write_options(f
, me
->mnt_opts
);
148 r
= fflush_and_check(f
);
150 return log_error_errno(r
, "Failed to write unit file %s: %m", name
);
152 /* use what as where, to have a nicer error message */
153 r
= generator_write_timeouts(arg_dest
, what
, what
, me
->mnt_opts
, NULL
);
157 if (flags
& MOUNT_MAKEFS
) {
158 r
= generator_hook_up_mkswap(arg_dest
, what
);
163 if (flags
& MOUNT_GROWFS
)
164 /* TODO: swap devices must be wiped and recreated */
165 log_warning("%s: growing swap devices is currently unsupported.", what
);
167 if (!(flags
& MOUNT_NOAUTO
)) {
168 r
= generator_add_symlink(arg_dest
, SPECIAL_SWAP_TARGET
,
169 (flags
& MOUNT_NOFAIL
) ? "wants" : "requires", name
);
177 static bool mount_is_network(struct mntent
*me
) {
180 return fstab_test_option(me
->mnt_opts
, "_netdev\0") ||
181 fstype_is_network(me
->mnt_type
);
184 static bool mount_in_initrd(struct mntent
*me
) {
187 return fstab_test_option(me
->mnt_opts
, "x-initrd.mount\0") ||
188 streq(me
->mnt_dir
, "/usr");
191 static int write_timeout(
196 const char *variable
) {
198 _cleanup_free_
char *timeout
= NULL
;
202 r
= fstab_filter_options(opts
, filter
, NULL
, &timeout
, NULL
, NULL
);
204 return log_warning_errno(r
, "Failed to parse options: %m");
208 r
= parse_sec_fix_0(timeout
, &u
);
210 log_warning("Failed to parse timeout for %s, ignoring: %s", where
, timeout
);
214 fprintf(f
, "%s=%s\n", variable
, FORMAT_TIMESPAN(u
, 0));
219 static int write_idle_timeout(FILE *f
, const char *where
, const char *opts
) {
220 return write_timeout(f
, where
, opts
,
221 "x-systemd.idle-timeout\0", "TimeoutIdleSec");
224 static int write_mount_timeout(FILE *f
, const char *where
, const char *opts
) {
225 return write_timeout(f
, where
, opts
,
226 "x-systemd.mount-timeout\0", "TimeoutSec");
229 static int write_dependency(
233 const char *format
) {
235 _cleanup_strv_free_
char **names
= NULL
, **units
= NULL
;
236 _cleanup_free_
char *res
= NULL
;
243 r
= fstab_filter_options(opts
, filter
, NULL
, NULL
, &names
, NULL
);
245 return log_warning_errno(r
, "Failed to parse options: %m");
249 STRV_FOREACH(s
, names
) {
252 r
= unit_name_mangle_with_suffix(*s
, "as dependency", 0, ".mount", &x
);
254 return log_error_errno(r
, "Failed to generate unit name: %m");
256 r
= strv_consume(&units
, x
);
262 res
= strv_join(units
, " ");
266 DISABLE_WARNING_FORMAT_NONLITERAL
;
267 fprintf(f
, format
, res
);
274 static int write_after(FILE *f
, const char *opts
) {
275 return write_dependency(f
, opts
,
276 "x-systemd.after\0", "After=%1$s\n");
279 static int write_requires_after(FILE *f
, const char *opts
) {
280 return write_dependency(f
, opts
,
281 "x-systemd.requires\0", "After=%1$s\nRequires=%1$s\n");
284 static int write_before(FILE *f
, const char *opts
) {
285 return write_dependency(f
, opts
,
286 "x-systemd.before\0", "Before=%1$s\n");
289 static int write_requires_mounts_for(FILE *f
, const char *opts
) {
290 _cleanup_strv_free_
char **paths
= NULL
, **paths_escaped
= NULL
;
291 _cleanup_free_
char *res
= NULL
;
297 r
= fstab_filter_options(opts
, "x-systemd.requires-mounts-for\0", NULL
, NULL
, &paths
, NULL
);
299 return log_warning_errno(r
, "Failed to parse options: %m");
303 r
= specifier_escape_strv(paths
, &paths_escaped
);
305 return log_error_errno(r
, "Failed to escape paths: %m");
307 res
= strv_join(paths_escaped
, " ");
311 fprintf(f
, "RequiresMountsFor=%s\n", res
);
316 static int write_extra_dependencies(FILE *f
, const char *opts
) {
322 r
= write_after(f
, opts
);
325 r
= write_requires_after(f
, opts
);
328 r
= write_before(f
, opts
);
331 r
= write_requires_mounts_for(f
, opts
);
339 static int add_mount(
343 const char *original_where
,
347 MountPointFlags flags
,
349 const char *source
) {
353 *automount_name
= NULL
,
355 *where_escaped
= NULL
;
356 _cleanup_strv_free_
char **wanted_by
= NULL
, **required_by
= NULL
;
357 _cleanup_fclose_
FILE *f
= NULL
;
366 if (streq_ptr(fstype
, "autofs"))
369 if (!is_path(where
)) {
370 log_warning("Mount point %s is not a valid path, ignoring.", where
);
374 if (mount_point_is_api(where
) ||
375 mount_point_ignore(where
))
378 r
= fstab_filter_options(opts
, "x-systemd.wanted-by\0", NULL
, NULL
, &wanted_by
, NULL
);
382 r
= fstab_filter_options(opts
, "x-systemd.required-by\0", NULL
, NULL
, &required_by
, NULL
);
386 if (path_equal(where
, "/")) {
387 if (flags
& MOUNT_NOAUTO
)
388 log_warning("Ignoring \"noauto\" option for root device");
389 if (flags
& MOUNT_NOFAIL
)
390 log_warning("Ignoring \"nofail\" option for root device");
391 if (flags
& MOUNT_AUTOMOUNT
)
392 log_warning("Ignoring \"automount\" option for root device");
393 if (!strv_isempty(wanted_by
))
394 log_warning("Ignoring \"x-systemd.wanted-by=\" option for root device");
395 if (!strv_isempty(required_by
))
396 log_warning("Ignoring \"x-systemd.required-by=\" option for root device");
398 required_by
= strv_free(required_by
);
399 wanted_by
= strv_free(wanted_by
);
400 SET_FLAG(flags
, MOUNT_NOAUTO
| MOUNT_NOFAIL
| MOUNT_AUTOMOUNT
, false);
403 r
= unit_name_from_path(where
, ".mount", &name
);
405 return log_error_errno(r
, "Failed to generate unit name: %m");
407 r
= generator_open_unit_file(dest
, fstab_path(), name
, &f
);
413 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n"
417 if (STRPTR_IN_SET(fstype
, "nfs", "nfs4") && !(flags
& MOUNT_AUTOMOUNT
) &&
418 fstab_test_yes_no_option(opts
, "bg\0" "fg\0")) {
419 /* The default retry timeout that mount.nfs uses for 'bg' mounts
420 * is 10000 minutes, where as it uses 2 minutes for 'fg' mounts.
421 * As we are making 'bg' mounts look like an 'fg' mount to
422 * mount.nfs (so systemd can manage the job-control aspects of 'bg'),
423 * we need to explicitly preserve that default, and also ensure
424 * the systemd mount-timeout doesn't interfere.
425 * By placing these options first, they can be overridden by
426 * settings in /etc/fstab. */
427 opts
= strjoina("x-systemd.mount-timeout=infinity,retry=10000,nofail,", opts
, ",fg");
428 SET_FLAG(flags
, MOUNT_NOFAIL
, true);
431 r
= write_extra_dependencies(f
, opts
);
435 /* Order the mount unit we generate relative to the post unit, so that DefaultDependencies= on the
436 * target unit won't affect us. */
437 if (post
&& !FLAGS_SET(flags
, MOUNT_AUTOMOUNT
) && !FLAGS_SET(flags
, MOUNT_NOAUTO
) &&
438 !FLAGS_SET(flags
, MOUNT_NOFAIL
))
439 fprintf(f
, "Before=%s\n", post
);
442 r
= generator_write_fsck_deps(f
, dest
, what
, where
, fstype
);
447 r
= generator_write_blockdev_dependency(f
, what
);
455 r
= write_what(f
, what
);
460 fprintf(f
, "# Canonicalized from %s\n", original_where
);
462 where_escaped
= specifier_escape(where
);
465 fprintf(f
, "Where=%s\n", where_escaped
);
467 if (!isempty(fstype
) && !streq(fstype
, "auto")) {
468 _cleanup_free_
char *t
= NULL
;
470 t
= specifier_escape(fstype
);
474 fprintf(f
, "Type=%s\n", t
);
477 r
= generator_write_timeouts(dest
, what
, where
, opts
, &filtered
);
481 r
= generator_write_device_deps(dest
, what
, where
, opts
);
485 r
= write_mount_timeout(f
, where
, opts
);
489 r
= write_options(f
, filtered
);
493 if (flags
& MOUNT_RW_ONLY
)
494 fprintf(f
, "ReadWriteOnly=yes\n");
496 r
= fflush_and_check(f
);
498 return log_error_errno(r
, "Failed to write unit file %s: %m", name
);
500 if (flags
& MOUNT_MAKEFS
) {
501 r
= generator_hook_up_mkfs(dest
, what
, where
, fstype
);
506 if (flags
& MOUNT_GROWFS
) {
507 r
= generator_hook_up_growfs(dest
, where
, post
);
512 if (!FLAGS_SET(flags
, MOUNT_AUTOMOUNT
)) {
513 if (!FLAGS_SET(flags
, MOUNT_NOAUTO
) && strv_isempty(wanted_by
) && strv_isempty(required_by
)) {
514 r
= generator_add_symlink(dest
, post
,
515 (flags
& MOUNT_NOFAIL
) ? "wants" : "requires", name
);
521 STRV_FOREACH(s
, wanted_by
) {
522 r
= generator_add_symlink(dest
, *s
, "wants", name
);
527 STRV_FOREACH(s
, required_by
) {
528 r
= generator_add_symlink(dest
, *s
, "requires", name
);
534 r
= unit_name_from_path(where
, ".automount", &automount_name
);
536 return log_error_errno(r
, "Failed to generate unit name: %m");
540 r
= generator_open_unit_file(dest
, fstab_path(), automount_name
, &f
);
547 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
556 r
= write_idle_timeout(f
, where
, opts
);
560 r
= fflush_and_check(f
);
562 return log_error_errno(r
, "Failed to write unit file %s: %m", automount_name
);
564 r
= generator_add_symlink(dest
, post
,
565 (flags
& MOUNT_NOFAIL
) ? "wants" : "requires", automount_name
);
573 static int parse_fstab(bool initrd
) {
574 _cleanup_endmntent_
FILE *f
= NULL
;
579 fstab
= initrd
? "/sysroot/etc/fstab" : fstab_path();
580 log_debug("Parsing %s...", fstab
);
582 f
= setmntent(fstab
, "re");
587 return log_error_errno(errno
, "Failed to open %s: %m", fstab
);
590 while ((me
= getmntent(f
))) {
591 _cleanup_free_
char *where
= NULL
, *what
= NULL
, *canonical_where
= NULL
;
592 bool makefs
, growfs
, noauto
, nofail
;
593 MountPointFlags flags
;
596 if (initrd
&& !mount_in_initrd(me
))
599 what
= fstab_node_to_udev_node(me
->mnt_fsname
);
603 if (is_device_path(what
) && path_is_read_only_fs("/sys") > 0) {
604 log_info("Running in a container, ignoring fstab device entry for %s.", what
);
608 where
= strdup(me
->mnt_dir
);
612 if (is_path(where
)) {
613 path_simplify(where
);
615 /* Follow symlinks here; see 5261ba901845c084de5a8fd06500ed09bfb0bd80 which makes sense for
616 * mount units, but causes problems since it historically worked to have symlinks in e.g.
617 * /etc/fstab. So we canonicalize here. Note that we use CHASE_NONEXISTENT to handle the case
618 * where a symlink refers to another mount target; this works assuming the sub-mountpoint
619 * target is the final directory. */
620 k
= chase_symlinks(where
, initrd
? "/sysroot" : NULL
,
621 CHASE_PREFIX_ROOT
| CHASE_NONEXISTENT
,
622 &canonical_where
, NULL
);
623 if (k
< 0) /* If we can't canonicalize we continue on as if it wasn't a symlink */
624 log_debug_errno(k
, "Failed to read symlink target for %s, ignoring: %m", where
);
625 else if (streq(canonical_where
, where
)) /* If it was fully canonicalized, suppress the change */
626 canonical_where
= mfree(canonical_where
);
628 log_debug("Canonicalized what=%s where=%s to %s", what
, where
, canonical_where
);
631 makefs
= fstab_test_option(me
->mnt_opts
, "x-systemd.makefs\0");
632 growfs
= fstab_test_option(me
->mnt_opts
, "x-systemd.growfs\0");
633 noauto
= fstab_test_yes_no_option(me
->mnt_opts
, "noauto\0" "auto\0");
634 nofail
= fstab_test_yes_no_option(me
->mnt_opts
, "nofail\0" "fail\0");
636 log_debug("Found entry what=%s where=%s type=%s makefs=%s growfs=%s noauto=%s nofail=%s",
637 what
, where
, me
->mnt_type
,
638 yes_no(makefs
), yes_no(growfs
),
639 yes_no(noauto
), yes_no(nofail
));
641 flags
= makefs
* MOUNT_MAKEFS
|
642 growfs
* MOUNT_GROWFS
|
643 noauto
* MOUNT_NOAUTO
|
644 nofail
* MOUNT_NOFAIL
;
646 if (streq(me
->mnt_type
, "swap"))
647 k
= add_swap(what
, me
, flags
);
649 bool rw_only
, automount
;
652 rw_only
= fstab_test_option(me
->mnt_opts
, "x-systemd.rw-only\0");
653 automount
= fstab_test_option(me
->mnt_opts
,
654 "comment=systemd.automount\0"
655 "x-systemd.automount\0");
657 flags
|= rw_only
* MOUNT_RW_ONLY
|
658 automount
* MOUNT_AUTOMOUNT
;
661 post
= SPECIAL_INITRD_FS_TARGET
;
662 else if (mount_is_network(me
))
663 post
= SPECIAL_REMOTE_FS_TARGET
;
665 post
= SPECIAL_LOCAL_FS_TARGET
;
667 k
= add_mount(arg_dest
,
669 canonical_where
?: where
,
670 canonical_where
? where
: NULL
,
686 static int add_sysroot_mount(void) {
687 _cleanup_free_
char *what
= NULL
;
688 const char *opts
, *fstype
;
692 if (isempty(arg_root_what
)) {
693 log_debug("Could not find a root= entry on the kernel command line.");
697 if (streq(arg_root_what
, "gpt-auto")) {
698 /* This is handled by the gpt-auto generator */
699 log_debug("Skipping root directory handling, as gpt-auto was requested.");
703 if (path_equal(arg_root_what
, "/dev/nfs")) {
704 /* This is handled by the kernel or the initrd */
705 log_debug("Skipping root directory handling, as /dev/nfs was requested.");
709 if (streq(arg_root_what
, "tmpfs")) {
710 /* If root=tmpfs is specified, then take this as shortcut for a writable tmpfs mount as root */
712 what
= strdup("rootfs"); /* just a pretty name, to show up in /proc/self/mountinfo */
716 fstype
= arg_root_fstype
?: "tmpfs"; /* tmpfs, unless overridden */
718 default_rw
= true; /* writable, unless overridden */;
721 what
= fstab_node_to_udev_node(arg_root_what
);
725 fstype
= arg_root_fstype
; /* if not specified explicitly, don't default to anything here */
727 default_rw
= false; /* read-only, unless overridden */
730 if (!arg_root_options
)
731 opts
= arg_root_rw
> 0 || (arg_root_rw
< 0 && default_rw
) ? "rw" : "ro";
732 else if (arg_root_rw
>= 0 ||
733 !fstab_test_option(arg_root_options
, "ro\0" "rw\0"))
734 opts
= strjoina(arg_root_options
, ",", arg_root_rw
> 0 ? "rw" : "ro");
736 opts
= arg_root_options
;
738 log_debug("Found entry what=%s where=/sysroot type=%s opts=%s", what
, strna(arg_root_fstype
), strempty(opts
));
740 if (is_device_path(what
)) {
741 r
= generator_write_initrd_root_device_deps(arg_dest
, what
);
746 return add_mount(arg_dest
,
752 is_device_path(what
) ? 1 : 0, /* passno */
753 0, /* makefs off, growfs off, noauto off, nofail off, automount off */
754 SPECIAL_INITRD_ROOT_FS_TARGET
,
758 static int add_sysroot_usr_mount(void) {
759 _cleanup_free_
char *what
= NULL
;
763 /* Returns 0 if we didn't do anything, > 0 if we either generated a unit for the /usr/ mount, or we
764 * know for sure something else did */
766 if (!arg_usr_what
&& !arg_usr_fstype
&& !arg_usr_options
)
769 if (arg_root_what
&& !arg_usr_what
) {
770 /* Copy over the root device, in case the /usr mount just differs in a mount option (consider btrfs subvolumes) */
771 arg_usr_what
= strdup(arg_root_what
);
776 if (arg_root_fstype
&& !arg_usr_fstype
) {
777 arg_usr_fstype
= strdup(arg_root_fstype
);
782 if (arg_root_options
&& !arg_usr_options
) {
783 arg_usr_options
= strdup(arg_root_options
);
784 if (!arg_usr_options
)
788 if (isempty(arg_usr_what
)) {
789 log_debug("Could not find a usr= entry on the kernel command line.");
793 if (streq(arg_usr_what
, "gpt-auto")) {
794 /* This is handled by the gpt-auto generator */
795 log_debug("Skipping /usr/ directory handling, as gpt-auto was requested.");
796 return 1; /* systemd-gpt-auto-generator will generate a unit for this, hence report that a
797 * unit file is being created for the host /usr/ mount. */
800 if (path_equal(arg_usr_what
, "/dev/nfs")) {
801 /* This is handled by the initrd (if at all supported, that is) */
802 log_debug("Skipping /usr/ directory handling, as /dev/nfs was requested.");
803 return 1; /* As above, report that NFS code will create the unit */
806 what
= fstab_node_to_udev_node(arg_usr_what
);
810 if (!arg_usr_options
)
811 opts
= arg_root_rw
> 0 ? "rw" : "ro";
812 else if (!fstab_test_option(arg_usr_options
, "ro\0" "rw\0"))
813 opts
= strjoina(arg_usr_options
, ",", arg_root_rw
> 0 ? "rw" : "ro");
815 opts
= arg_usr_options
;
817 /* When mounting /usr from the initrd, we add an extra level of indirection: we first mount the /usr/
818 * partition to /sysusr/usr/, and then afterwards bind mount that to /sysroot/usr/. We do this so
819 * that we can cover for systems that initially only have a /usr/ around and where the root fs needs
820 * to be synthesized, based on configuration included in /usr/, e.g. systemd-repart. Software like
821 * this should order itself after initrd-usr-fs.target and before initrd-fs.target; and it should
822 * look into both /sysusr/ and /sysroot/ for the configuration data to apply. */
824 log_debug("Found entry what=%s where=/sysusr/usr type=%s opts=%s", what
, strna(arg_usr_fstype
), strempty(opts
));
826 r
= add_mount(arg_dest
,
832 is_device_path(what
) ? 1 : 0, /* passno */
834 SPECIAL_INITRD_USR_FS_TARGET
,
839 log_debug("Synthesizing entry what=/sysusr/usr where=/sysrootr/usr opts=bind");
841 r
= add_mount(arg_dest
,
849 SPECIAL_INITRD_FS_TARGET
,
857 static int add_sysroot_usr_mount_or_fallback(void) {
860 r
= add_sysroot_usr_mount();
864 /* OK, so we didn't write anything out for /sysusr/usr/ nor /sysroot/usr/. In this case, let's make
865 * sure that initrd-usr-fs.target is at least ordered after sysroot.mount so that services that order
866 * themselves get the guarantee that /usr/ is definitely mounted somewhere. */
868 return generator_add_symlink(
870 SPECIAL_INITRD_USR_FS_TARGET
,
875 static int add_volatile_root(void) {
877 /* Let's add in systemd-remount-volatile.service which will remount the root device to tmpfs if this is
878 * requested (or as an overlayfs), leaving only /usr from the root mount inside. */
880 if (!IN_SET(arg_volatile_mode
, VOLATILE_YES
, VOLATILE_OVERLAY
))
883 return generator_add_symlink(arg_dest
, SPECIAL_INITRD_ROOT_FS_TARGET
, "requires",
884 SYSTEM_DATA_UNIT_DIR
"/" SPECIAL_VOLATILE_ROOT_SERVICE
);
887 static int add_volatile_var(void) {
889 if (arg_volatile_mode
!= VOLATILE_STATE
)
892 /* If requested, mount /var as tmpfs, but do so only if there's nothing else defined for this. */
894 return add_mount(arg_dest_late
,
899 "mode=0755" TMPFS_LIMITS_VAR
,
902 SPECIAL_LOCAL_FS_TARGET
,
906 static int parse_proc_cmdline_item(const char *key
, const char *value
, void *data
) {
909 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
910 * instance should take precedence. In the case of multiple rootflags=
911 * or usrflags= the arguments should be concatenated */
913 if (STR_IN_SET(key
, "fstab", "rd.fstab")) {
915 r
= value
? parse_boolean(value
) : 1;
917 log_warning("Failed to parse fstab switch %s. Ignoring.", value
);
919 arg_fstab_enabled
= r
;
921 } else if (streq(key
, "root")) {
923 if (proc_cmdline_value_missing(key
, value
))
926 return free_and_strdup_warn(&arg_root_what
, value
);
928 } else if (streq(key
, "rootfstype")) {
930 if (proc_cmdline_value_missing(key
, value
))
933 return free_and_strdup_warn(&arg_root_fstype
, value
);
935 } else if (streq(key
, "rootflags")) {
937 if (proc_cmdline_value_missing(key
, value
))
940 if (!strextend_with_separator(&arg_root_options
, ",", value
))
943 } else if (streq(key
, "roothash")) {
945 if (proc_cmdline_value_missing(key
, value
))
948 return free_and_strdup_warn(&arg_root_hash
, value
);
950 } else if (streq(key
, "mount.usr")) {
952 if (proc_cmdline_value_missing(key
, value
))
955 return free_and_strdup_warn(&arg_usr_what
, value
);
957 } else if (streq(key
, "mount.usrfstype")) {
959 if (proc_cmdline_value_missing(key
, value
))
962 return free_and_strdup_warn(&arg_usr_fstype
, value
);
964 } else if (streq(key
, "mount.usrflags")) {
966 if (proc_cmdline_value_missing(key
, value
))
969 if (!strextend_with_separator(&arg_usr_options
, ",", value
))
972 } else if (streq(key
, "rw") && !value
)
974 else if (streq(key
, "ro") && !value
)
976 else if (streq(key
, "systemd.volatile")) {
980 m
= volatile_mode_from_string(value
);
982 log_warning_errno(m
, "Failed to parse systemd.volatile= argument: %s", value
);
984 arg_volatile_mode
= m
;
986 arg_volatile_mode
= VOLATILE_YES
;
988 } else if (streq(key
, "systemd.swap")) {
990 r
= value
? parse_boolean(value
) : 1;
992 log_warning("Failed to parse systemd.swap switch %s. Ignoring.", value
);
994 arg_swap_enabled
= r
;
1000 static int determine_root(void) {
1001 /* If we have a root hash but no root device then Verity is used, and we use the "root" DM device as root. */
1009 arg_root_what
= strdup("/dev/mapper/root");
1013 log_info("Using verity root device %s.", arg_root_what
);
1018 static int run(const char *dest
, const char *dest_early
, const char *dest_late
) {
1019 int r
, r2
= 0, r3
= 0;
1021 assert_se(arg_dest
= dest
);
1022 assert_se(arg_dest_late
= dest_late
);
1024 r
= proc_cmdline_parse(parse_proc_cmdline_item
, NULL
, 0);
1026 log_warning_errno(r
, "Failed to parse kernel command line, ignoring: %m");
1028 (void) determine_root();
1030 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
1032 r
= add_sysroot_mount();
1034 r2
= add_sysroot_usr_mount_or_fallback();
1036 r3
= add_volatile_root();
1038 r
= add_volatile_var();
1040 /* Honour /etc/fstab only when that's enabled */
1041 if (arg_fstab_enabled
) {
1042 /* Parse the local /etc/fstab, possibly from the initrd */
1043 r2
= parse_fstab(false);
1045 /* If running in the initrd also parse the /etc/fstab from the host */
1047 r3
= parse_fstab(true);
1049 r3
= generator_enable_remount_fs_service(arg_dest
);
1052 return r
< 0 ? r
: r2
< 0 ? r2
: r3
;
1055 DEFINE_MAIN_GENERATOR_FUNCTION(run
);