1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 #include "alloc-util.h"
8 #include "chase-symlinks.h"
11 #include "fstab-util.h"
12 #include "generator.h"
13 #include "in-addr-util.h"
15 #include "main-func.h"
17 #include "mount-setup.h"
18 #include "mount-util.h"
19 #include "mountpoint-util.h"
20 #include "parse-util.h"
21 #include "path-util.h"
22 #include "proc-cmdline.h"
24 #include "specifier.h"
25 #include "stat-util.h"
26 #include "string-util.h"
28 #include "unit-name.h"
31 #include "volatile-util.h"
33 typedef enum MountPointFlags
{
34 MOUNT_NOAUTO
= 1 << 0,
35 MOUNT_NOFAIL
= 1 << 1,
36 MOUNT_AUTOMOUNT
= 1 << 2,
37 MOUNT_MAKEFS
= 1 << 3,
38 MOUNT_GROWFS
= 1 << 4,
39 MOUNT_RW_ONLY
= 1 << 5,
42 static const char *arg_dest
= NULL
;
43 static const char *arg_dest_late
= NULL
;
44 static bool arg_fstab_enabled
= true;
45 static bool arg_swap_enabled
= true;
46 static char *arg_root_what
= NULL
;
47 static char *arg_root_fstype
= NULL
;
48 static char *arg_root_options
= NULL
;
49 static char *arg_root_hash
= NULL
;
50 static int arg_root_rw
= -1;
51 static char *arg_usr_what
= NULL
;
52 static char *arg_usr_fstype
= NULL
;
53 static char *arg_usr_options
= NULL
;
54 static char *arg_usr_hash
= NULL
;
55 static VolatileMode arg_volatile_mode
= _VOLATILE_MODE_INVALID
;
57 STATIC_DESTRUCTOR_REGISTER(arg_root_what
, freep
);
58 STATIC_DESTRUCTOR_REGISTER(arg_root_fstype
, freep
);
59 STATIC_DESTRUCTOR_REGISTER(arg_root_options
, freep
);
60 STATIC_DESTRUCTOR_REGISTER(arg_root_hash
, freep
);
61 STATIC_DESTRUCTOR_REGISTER(arg_usr_what
, freep
);
62 STATIC_DESTRUCTOR_REGISTER(arg_usr_fstype
, freep
);
63 STATIC_DESTRUCTOR_REGISTER(arg_usr_options
, freep
);
64 STATIC_DESTRUCTOR_REGISTER(arg_usr_hash
, freep
);
66 static int write_options(FILE *f
, const char *options
) {
67 _cleanup_free_
char *o
= NULL
;
72 if (streq(options
, "defaults"))
75 o
= specifier_escape(options
);
79 fprintf(f
, "Options=%s\n", o
);
83 static int write_what(FILE *f
, const char *what
) {
84 _cleanup_free_
char *w
= NULL
;
86 w
= specifier_escape(what
);
90 fprintf(f
, "What=%s\n", w
);
97 MountPointFlags flags
) {
99 _cleanup_free_
char *name
= NULL
;
100 _cleanup_fclose_
FILE *f
= NULL
;
106 if (!arg_swap_enabled
) {
107 log_info("Swap unit generation disabled on kernel command line, ignoring fstab swap entry for %s.", what
);
111 if (access("/proc/swaps", F_OK
) < 0) {
112 log_info("Swap not supported, ignoring fstab swap entry for %s.", what
);
116 if (detect_container() > 0) {
117 log_info("Running in a container, ignoring fstab swap entry for %s.", what
);
121 r
= unit_name_from_path(what
, ".swap", &name
);
123 return log_error_errno(r
, "Failed to generate unit name: %m");
125 r
= generator_open_unit_file(arg_dest
, fstab_path(), name
, &f
);
131 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n"
135 r
= generator_write_blockdev_dependency(f
, what
);
143 r
= write_what(f
, what
);
147 r
= write_options(f
, me
->mnt_opts
);
151 r
= fflush_and_check(f
);
153 return log_error_errno(r
, "Failed to write unit file %s: %m", name
);
155 /* use what as where, to have a nicer error message */
156 r
= generator_write_timeouts(arg_dest
, what
, what
, me
->mnt_opts
, NULL
);
160 if (flags
& MOUNT_MAKEFS
) {
161 r
= generator_hook_up_mkswap(arg_dest
, what
);
166 if (flags
& MOUNT_GROWFS
)
167 /* TODO: swap devices must be wiped and recreated */
168 log_warning("%s: growing swap devices is currently unsupported.", what
);
170 if (!(flags
& MOUNT_NOAUTO
)) {
171 r
= generator_add_symlink(arg_dest
, SPECIAL_SWAP_TARGET
,
172 (flags
& MOUNT_NOFAIL
) ? "wants" : "requires", name
);
180 static bool mount_is_network(struct mntent
*me
) {
183 return fstab_test_option(me
->mnt_opts
, "_netdev\0") ||
184 fstype_is_network(me
->mnt_type
);
187 static bool mount_in_initrd(struct mntent
*me
) {
190 return fstab_test_option(me
->mnt_opts
, "x-initrd.mount\0") ||
191 streq(me
->mnt_dir
, "/usr");
194 static int write_timeout(
199 const char *variable
) {
201 _cleanup_free_
char *timeout
= NULL
;
205 r
= fstab_filter_options(opts
, filter
, NULL
, &timeout
, NULL
, NULL
);
207 return log_warning_errno(r
, "Failed to parse options: %m");
211 r
= parse_sec_fix_0(timeout
, &u
);
213 log_warning("Failed to parse timeout for %s, ignoring: %s", where
, timeout
);
217 fprintf(f
, "%s=%s\n", variable
, FORMAT_TIMESPAN(u
, 0));
222 static int write_idle_timeout(FILE *f
, const char *where
, const char *opts
) {
223 return write_timeout(f
, where
, opts
,
224 "x-systemd.idle-timeout\0", "TimeoutIdleSec");
227 static int write_mount_timeout(FILE *f
, const char *where
, const char *opts
) {
228 return write_timeout(f
, where
, opts
,
229 "x-systemd.mount-timeout\0", "TimeoutSec");
232 static int write_dependency(
236 const char *format
) {
238 _cleanup_strv_free_
char **names
= NULL
, **units
= NULL
;
239 _cleanup_free_
char *res
= NULL
;
246 r
= fstab_filter_options(opts
, filter
, NULL
, NULL
, &names
, NULL
);
248 return log_warning_errno(r
, "Failed to parse options: %m");
252 STRV_FOREACH(s
, names
) {
255 r
= unit_name_mangle_with_suffix(*s
, "as dependency", 0, ".mount", &x
);
257 return log_error_errno(r
, "Failed to generate unit name: %m");
259 r
= strv_consume(&units
, x
);
265 res
= strv_join(units
, " ");
269 DISABLE_WARNING_FORMAT_NONLITERAL
;
270 fprintf(f
, format
, res
);
277 static int write_after(FILE *f
, const char *opts
) {
278 return write_dependency(f
, opts
,
279 "x-systemd.after\0", "After=%1$s\n");
282 static int write_requires_after(FILE *f
, const char *opts
) {
283 return write_dependency(f
, opts
,
284 "x-systemd.requires\0", "After=%1$s\nRequires=%1$s\n");
287 static int write_before(FILE *f
, const char *opts
) {
288 return write_dependency(f
, opts
,
289 "x-systemd.before\0", "Before=%1$s\n");
292 static int write_requires_mounts_for(FILE *f
, const char *opts
) {
293 _cleanup_strv_free_
char **paths
= NULL
, **paths_escaped
= NULL
;
294 _cleanup_free_
char *res
= NULL
;
300 r
= fstab_filter_options(opts
, "x-systemd.requires-mounts-for\0", NULL
, NULL
, &paths
, NULL
);
302 return log_warning_errno(r
, "Failed to parse options: %m");
306 r
= specifier_escape_strv(paths
, &paths_escaped
);
308 return log_error_errno(r
, "Failed to escape paths: %m");
310 res
= strv_join(paths_escaped
, " ");
314 fprintf(f
, "RequiresMountsFor=%s\n", res
);
319 static int write_extra_dependencies(FILE *f
, const char *opts
) {
325 r
= write_after(f
, opts
);
328 r
= write_requires_after(f
, opts
);
331 r
= write_before(f
, opts
);
334 r
= write_requires_mounts_for(f
, opts
);
342 static int add_mount(
346 const char *original_where
,
350 MountPointFlags flags
,
352 const char *source
) {
356 *automount_name
= NULL
,
358 *where_escaped
= NULL
;
359 _cleanup_strv_free_
char **wanted_by
= NULL
, **required_by
= NULL
;
360 _cleanup_fclose_
FILE *f
= NULL
;
369 if (streq_ptr(fstype
, "autofs"))
372 if (!is_path(where
)) {
373 log_warning("Mount point %s is not a valid path, ignoring.", where
);
377 if (mount_point_is_api(where
) ||
378 mount_point_ignore(where
))
381 r
= fstab_filter_options(opts
, "x-systemd.wanted-by\0", NULL
, NULL
, &wanted_by
, NULL
);
385 r
= fstab_filter_options(opts
, "x-systemd.required-by\0", NULL
, NULL
, &required_by
, NULL
);
389 if (path_equal(where
, "/")) {
390 if (flags
& MOUNT_NOAUTO
)
391 log_warning("Ignoring \"noauto\" option for root device");
392 if (flags
& MOUNT_NOFAIL
)
393 log_warning("Ignoring \"nofail\" option for root device");
394 if (flags
& MOUNT_AUTOMOUNT
)
395 log_warning("Ignoring \"automount\" option for root device");
396 if (!strv_isempty(wanted_by
))
397 log_warning("Ignoring \"x-systemd.wanted-by=\" option for root device");
398 if (!strv_isempty(required_by
))
399 log_warning("Ignoring \"x-systemd.required-by=\" option for root device");
401 required_by
= strv_free(required_by
);
402 wanted_by
= strv_free(wanted_by
);
403 SET_FLAG(flags
, MOUNT_NOAUTO
| MOUNT_NOFAIL
| MOUNT_AUTOMOUNT
, false);
406 r
= unit_name_from_path(where
, ".mount", &name
);
408 return log_error_errno(r
, "Failed to generate unit name: %m");
410 r
= generator_open_unit_file(dest
, fstab_path(), name
, &f
);
416 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n"
420 if (STRPTR_IN_SET(fstype
, "nfs", "nfs4") && !(flags
& MOUNT_AUTOMOUNT
) &&
421 fstab_test_yes_no_option(opts
, "bg\0" "fg\0")) {
422 /* The default retry timeout that mount.nfs uses for 'bg' mounts
423 * is 10000 minutes, where as it uses 2 minutes for 'fg' mounts.
424 * As we are making 'bg' mounts look like an 'fg' mount to
425 * mount.nfs (so systemd can manage the job-control aspects of 'bg'),
426 * we need to explicitly preserve that default, and also ensure
427 * the systemd mount-timeout doesn't interfere.
428 * By placing these options first, they can be overridden by
429 * settings in /etc/fstab. */
430 opts
= strjoina("x-systemd.mount-timeout=infinity,retry=10000,nofail,", opts
, ",fg");
431 SET_FLAG(flags
, MOUNT_NOFAIL
, true);
434 r
= write_extra_dependencies(f
, opts
);
438 /* Order the mount unit we generate relative to the post unit, so that DefaultDependencies= on the
439 * target unit won't affect us. */
440 if (post
&& !FLAGS_SET(flags
, MOUNT_NOFAIL
))
441 fprintf(f
, "Before=%s\n", post
);
444 r
= generator_write_fsck_deps(f
, dest
, what
, where
, fstype
);
449 r
= generator_write_blockdev_dependency(f
, what
);
457 r
= write_what(f
, what
);
462 fprintf(f
, "# Canonicalized from %s\n", original_where
);
464 where_escaped
= specifier_escape(where
);
467 fprintf(f
, "Where=%s\n", where_escaped
);
469 if (!isempty(fstype
) && !streq(fstype
, "auto")) {
470 _cleanup_free_
char *t
= NULL
;
472 t
= specifier_escape(fstype
);
476 fprintf(f
, "Type=%s\n", t
);
479 r
= generator_write_timeouts(dest
, what
, where
, opts
, &filtered
);
483 r
= generator_write_device_deps(dest
, what
, where
, opts
);
487 r
= write_mount_timeout(f
, where
, opts
);
491 r
= write_options(f
, filtered
);
495 if (flags
& MOUNT_RW_ONLY
)
496 fprintf(f
, "ReadWriteOnly=yes\n");
498 r
= fflush_and_check(f
);
500 return log_error_errno(r
, "Failed to write unit file %s: %m", name
);
502 if (flags
& MOUNT_MAKEFS
) {
503 r
= generator_hook_up_mkfs(dest
, what
, where
, fstype
);
508 if (flags
& MOUNT_GROWFS
) {
509 r
= generator_hook_up_growfs(dest
, where
, post
);
514 if (!FLAGS_SET(flags
, MOUNT_AUTOMOUNT
)) {
515 if (!FLAGS_SET(flags
, MOUNT_NOAUTO
) && strv_isempty(wanted_by
) && strv_isempty(required_by
)) {
516 r
= generator_add_symlink(dest
, post
,
517 (flags
& MOUNT_NOFAIL
) ? "wants" : "requires", name
);
523 STRV_FOREACH(s
, wanted_by
) {
524 r
= generator_add_symlink(dest
, *s
, "wants", name
);
529 STRV_FOREACH(s
, required_by
) {
530 r
= generator_add_symlink(dest
, *s
, "requires", name
);
536 r
= unit_name_from_path(where
, ".automount", &automount_name
);
538 return log_error_errno(r
, "Failed to generate unit name: %m");
542 r
= generator_open_unit_file(dest
, fstab_path(), automount_name
, &f
);
549 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
558 r
= write_idle_timeout(f
, where
, opts
);
562 r
= fflush_and_check(f
);
564 return log_error_errno(r
, "Failed to write unit file %s: %m", automount_name
);
566 r
= generator_add_symlink(dest
, post
,
567 (flags
& MOUNT_NOFAIL
) ? "wants" : "requires", automount_name
);
575 static int parse_fstab(bool initrd
) {
576 _cleanup_endmntent_
FILE *f
= NULL
;
581 fstab
= initrd
? "/sysroot/etc/fstab" : fstab_path();
582 log_debug("Parsing %s...", fstab
);
584 f
= setmntent(fstab
, "re");
589 return log_error_errno(errno
, "Failed to open %s: %m", fstab
);
592 while ((me
= getmntent(f
))) {
593 _cleanup_free_
char *where
= NULL
, *what
= NULL
, *canonical_where
= NULL
;
594 bool makefs
, growfs
, noauto
, nofail
;
595 MountPointFlags flags
;
598 if (initrd
&& !mount_in_initrd(me
))
601 what
= fstab_node_to_udev_node(me
->mnt_fsname
);
605 if (path_is_read_only_fs("/sys") > 0) {
606 if (streq(what
, "sysfs")) {
607 log_info("Running in a container, ignoring fstab entry for %s.", what
);
611 if (is_device_path(what
)) {
612 log_info("Running in a container, ignoring fstab device entry for %s.", what
);
617 where
= strdup(me
->mnt_dir
);
621 if (is_path(where
)) {
622 path_simplify(where
);
624 /* Follow symlinks here; see 5261ba901845c084de5a8fd06500ed09bfb0bd80 which makes sense for
625 * mount units, but causes problems since it historically worked to have symlinks in e.g.
626 * /etc/fstab. So we canonicalize here. Note that we use CHASE_NONEXISTENT to handle the case
627 * where a symlink refers to another mount target; this works assuming the sub-mountpoint
628 * target is the final directory. */
629 k
= chase_symlinks(where
, initrd
? "/sysroot" : NULL
,
630 CHASE_PREFIX_ROOT
| CHASE_NONEXISTENT
,
631 &canonical_where
, NULL
);
632 if (k
< 0) /* If we can't canonicalize we continue on as if it wasn't a symlink */
633 log_debug_errno(k
, "Failed to read symlink target for %s, ignoring: %m", where
);
634 else if (streq(canonical_where
, where
)) /* If it was fully canonicalized, suppress the change */
635 canonical_where
= mfree(canonical_where
);
637 log_debug("Canonicalized what=%s where=%s to %s", what
, where
, canonical_where
);
640 makefs
= fstab_test_option(me
->mnt_opts
, "x-systemd.makefs\0");
641 growfs
= fstab_test_option(me
->mnt_opts
, "x-systemd.growfs\0");
642 noauto
= fstab_test_yes_no_option(me
->mnt_opts
, "noauto\0" "auto\0");
643 nofail
= fstab_test_yes_no_option(me
->mnt_opts
, "nofail\0" "fail\0");
645 log_debug("Found entry what=%s where=%s type=%s makefs=%s growfs=%s noauto=%s nofail=%s",
646 what
, where
, me
->mnt_type
,
647 yes_no(makefs
), yes_no(growfs
),
648 yes_no(noauto
), yes_no(nofail
));
650 flags
= makefs
* MOUNT_MAKEFS
|
651 growfs
* MOUNT_GROWFS
|
652 noauto
* MOUNT_NOAUTO
|
653 nofail
* MOUNT_NOFAIL
;
655 if (streq(me
->mnt_type
, "swap"))
656 k
= add_swap(what
, me
, flags
);
658 bool rw_only
, automount
;
661 rw_only
= fstab_test_option(me
->mnt_opts
, "x-systemd.rw-only\0");
662 automount
= fstab_test_option(me
->mnt_opts
,
663 "comment=systemd.automount\0"
664 "x-systemd.automount\0");
666 flags
|= rw_only
* MOUNT_RW_ONLY
|
667 automount
* MOUNT_AUTOMOUNT
;
670 post
= SPECIAL_INITRD_FS_TARGET
;
671 else if (mount_is_network(me
))
672 post
= SPECIAL_REMOTE_FS_TARGET
;
674 post
= SPECIAL_LOCAL_FS_TARGET
;
676 k
= add_mount(arg_dest
,
678 canonical_where
?: where
,
679 canonical_where
? where
: NULL
,
695 static int sysroot_is_nfsroot(void) {
696 union in_addr_union u
;
700 assert(arg_root_what
);
702 /* From dracut.cmdline(7).
704 * root=[<server-ip>:]<root-dir>[:<nfs-options>]
705 * root=nfs:[<server-ip>:]<root-dir>[:<nfs-options>],
706 * root=nfs4:[<server-ip>:]<root-dir>[:<nfs-options>],
709 * mount nfs share from <server-ip>:/<root-dir>, if no server-ip is given, use dhcp next_server.
710 * If server-ip is an IPv6 address it has to be put in brackets, e.g. [2001:DB8::1]. NFS options
711 * can be appended with the prefix ":" or "," and are separated by ",". */
713 if (path_equal(arg_root_what
, "/dev/nfs") ||
714 STR_IN_SET(arg_root_what
, "dhcp", "dhcp6") ||
715 STARTSWITH_SET(arg_root_what
, "nfs:", "nfs4:"))
719 if (arg_root_what
[0] == '[') {
720 sep
= strchr(arg_root_what
+ 1, ']');
724 a
= strndupa(arg_root_what
+ 1, sep
- arg_root_what
- 1);
726 r
= in_addr_from_string(AF_INET6
, a
, &u
);
734 sep
= strchr(arg_root_what
, ':');
736 a
= strndupa(arg_root_what
, sep
- arg_root_what
);
738 if (in_addr_from_string(AF_INET
, a
, &u
) >= 0)
742 /* root directory without address */
743 return path_is_absolute(arg_root_what
) && !path_startswith(arg_root_what
, "/dev");
746 static int add_sysroot_mount(void) {
747 _cleanup_free_
char *what
= NULL
;
748 const char *opts
, *fstype
;
752 if (isempty(arg_root_what
)) {
753 log_debug("Could not find a root= entry on the kernel command line.");
757 if (streq(arg_root_what
, "gpt-auto")) {
758 /* This is handled by the gpt-auto generator */
759 log_debug("Skipping root directory handling, as gpt-auto was requested.");
763 r
= sysroot_is_nfsroot();
765 log_debug_errno(r
, "Failed to determine if the root directory is on NFS, assuming not: %m");
767 /* This is handled by the kernel or the initrd */
768 log_debug("Skipping root directory handling, as root on NFS was requested.");
772 if (startswith(arg_root_what
, "cifs://")) {
773 log_debug("Skipping root directory handling, as root on CIFS was requested.");
777 if (startswith(arg_root_what
, "iscsi:")) {
778 log_debug("Skipping root directory handling, as root on iSCSI was requested.");
782 if (startswith(arg_root_what
, "live:")) {
783 log_debug("Skipping root directory handling, as root on live image was requested.");
787 if (streq(arg_root_what
, "tmpfs")) {
788 /* If root=tmpfs is specified, then take this as shortcut for a writable tmpfs mount as root */
790 what
= strdup("rootfs"); /* just a pretty name, to show up in /proc/self/mountinfo */
794 fstype
= arg_root_fstype
?: "tmpfs"; /* tmpfs, unless overridden */
796 default_rw
= true; /* writable, unless overridden */;
799 what
= fstab_node_to_udev_node(arg_root_what
);
803 fstype
= arg_root_fstype
; /* if not specified explicitly, don't default to anything here */
805 default_rw
= false; /* read-only, unless overridden */
808 if (!arg_root_options
)
809 opts
= arg_root_rw
> 0 || (arg_root_rw
< 0 && default_rw
) ? "rw" : "ro";
810 else if (arg_root_rw
>= 0 ||
811 !fstab_test_option(arg_root_options
, "ro\0" "rw\0"))
812 opts
= strjoina(arg_root_options
, ",", arg_root_rw
> 0 ? "rw" : "ro");
814 opts
= arg_root_options
;
816 log_debug("Found entry what=%s where=/sysroot type=%s opts=%s", what
, strna(arg_root_fstype
), strempty(opts
));
818 if (is_device_path(what
)) {
819 r
= generator_write_initrd_root_device_deps(arg_dest
, what
);
824 return add_mount(arg_dest
,
830 is_device_path(what
) ? 1 : 0, /* passno */
831 0, /* makefs off, growfs off, noauto off, nofail off, automount off */
832 SPECIAL_INITRD_ROOT_FS_TARGET
,
836 static int add_sysroot_usr_mount(void) {
837 _cleanup_free_
char *what
= NULL
;
841 /* Returns 0 if we didn't do anything, > 0 if we either generated a unit for the /usr/ mount, or we
842 * know for sure something else did */
844 if (!arg_usr_what
&& !arg_usr_fstype
&& !arg_usr_options
)
847 if (arg_root_what
&& !arg_usr_what
) {
848 /* Copy over the root device, in case the /usr mount just differs in a mount option (consider btrfs subvolumes) */
849 arg_usr_what
= strdup(arg_root_what
);
854 if (arg_root_fstype
&& !arg_usr_fstype
) {
855 arg_usr_fstype
= strdup(arg_root_fstype
);
860 if (arg_root_options
&& !arg_usr_options
) {
861 arg_usr_options
= strdup(arg_root_options
);
862 if (!arg_usr_options
)
866 if (isempty(arg_usr_what
)) {
867 log_debug("Could not find a usr= entry on the kernel command line.");
871 if (streq(arg_usr_what
, "gpt-auto")) {
872 /* This is handled by the gpt-auto generator */
873 log_debug("Skipping /usr/ directory handling, as gpt-auto was requested.");
874 return 1; /* systemd-gpt-auto-generator will generate a unit for this, hence report that a
875 * unit file is being created for the host /usr/ mount. */
878 if (path_equal(arg_usr_what
, "/dev/nfs")) {
879 /* This is handled by the initrd (if at all supported, that is) */
880 log_debug("Skipping /usr/ directory handling, as /dev/nfs was requested.");
881 return 1; /* As above, report that NFS code will create the unit */
884 what
= fstab_node_to_udev_node(arg_usr_what
);
888 if (!arg_usr_options
)
889 opts
= arg_root_rw
> 0 ? "rw" : "ro";
890 else if (!fstab_test_option(arg_usr_options
, "ro\0" "rw\0"))
891 opts
= strjoina(arg_usr_options
, ",", arg_root_rw
> 0 ? "rw" : "ro");
893 opts
= arg_usr_options
;
895 /* When mounting /usr from the initrd, we add an extra level of indirection: we first mount the /usr/
896 * partition to /sysusr/usr/, and then afterwards bind mount that to /sysroot/usr/. We do this so
897 * that we can cover for systems that initially only have a /usr/ around and where the root fs needs
898 * to be synthesized, based on configuration included in /usr/, e.g. systemd-repart. Software like
899 * this should order itself after initrd-usr-fs.target and before initrd-fs.target; and it should
900 * look into both /sysusr/ and /sysroot/ for the configuration data to apply. */
902 log_debug("Found entry what=%s where=/sysusr/usr type=%s opts=%s", what
, strna(arg_usr_fstype
), strempty(opts
));
904 r
= add_mount(arg_dest
,
910 is_device_path(what
) ? 1 : 0, /* passno */
912 SPECIAL_INITRD_USR_FS_TARGET
,
917 log_debug("Synthesizing entry what=/sysusr/usr where=/sysrootr/usr opts=bind");
919 r
= add_mount(arg_dest
,
927 SPECIAL_INITRD_FS_TARGET
,
935 static int add_sysroot_usr_mount_or_fallback(void) {
938 r
= add_sysroot_usr_mount();
942 /* OK, so we didn't write anything out for /sysusr/usr/ nor /sysroot/usr/. In this case, let's make
943 * sure that initrd-usr-fs.target is at least ordered after sysroot.mount so that services that order
944 * themselves get the guarantee that /usr/ is definitely mounted somewhere. */
946 return generator_add_symlink(
948 SPECIAL_INITRD_USR_FS_TARGET
,
953 static int add_volatile_root(void) {
955 /* Let's add in systemd-remount-volatile.service which will remount the root device to tmpfs if this is
956 * requested (or as an overlayfs), leaving only /usr from the root mount inside. */
958 if (!IN_SET(arg_volatile_mode
, VOLATILE_YES
, VOLATILE_OVERLAY
))
961 return generator_add_symlink(arg_dest
, SPECIAL_INITRD_ROOT_FS_TARGET
, "requires",
962 SYSTEM_DATA_UNIT_DIR
"/" SPECIAL_VOLATILE_ROOT_SERVICE
);
965 static int add_volatile_var(void) {
967 if (arg_volatile_mode
!= VOLATILE_STATE
)
970 /* If requested, mount /var as tmpfs, but do so only if there's nothing else defined for this. */
972 return add_mount(arg_dest_late
,
977 "mode=0755" TMPFS_LIMITS_VAR
,
980 SPECIAL_LOCAL_FS_TARGET
,
984 static int parse_proc_cmdline_item(const char *key
, const char *value
, void *data
) {
987 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
988 * instance should take precedence. In the case of multiple rootflags=
989 * or usrflags= the arguments should be concatenated */
991 if (STR_IN_SET(key
, "fstab", "rd.fstab")) {
993 r
= value
? parse_boolean(value
) : 1;
995 log_warning("Failed to parse fstab switch %s. Ignoring.", value
);
997 arg_fstab_enabled
= r
;
999 } else if (streq(key
, "root")) {
1001 if (proc_cmdline_value_missing(key
, value
))
1004 return free_and_strdup_warn(&arg_root_what
, value
);
1006 } else if (streq(key
, "rootfstype")) {
1008 if (proc_cmdline_value_missing(key
, value
))
1011 return free_and_strdup_warn(&arg_root_fstype
, value
);
1013 } else if (streq(key
, "rootflags")) {
1015 if (proc_cmdline_value_missing(key
, value
))
1018 if (!strextend_with_separator(&arg_root_options
, ",", value
))
1021 } else if (streq(key
, "roothash")) {
1023 if (proc_cmdline_value_missing(key
, value
))
1026 return free_and_strdup_warn(&arg_root_hash
, value
);
1028 } else if (streq(key
, "mount.usr")) {
1030 if (proc_cmdline_value_missing(key
, value
))
1033 return free_and_strdup_warn(&arg_usr_what
, value
);
1035 } else if (streq(key
, "mount.usrfstype")) {
1037 if (proc_cmdline_value_missing(key
, value
))
1040 return free_and_strdup_warn(&arg_usr_fstype
, value
);
1042 } else if (streq(key
, "mount.usrflags")) {
1044 if (proc_cmdline_value_missing(key
, value
))
1047 if (!strextend_with_separator(&arg_usr_options
, ",", value
))
1050 } else if (streq(key
, "usrhash")) {
1052 if (proc_cmdline_value_missing(key
, value
))
1055 return free_and_strdup_warn(&arg_usr_hash
, value
);
1057 } else if (streq(key
, "rw") && !value
)
1059 else if (streq(key
, "ro") && !value
)
1060 arg_root_rw
= false;
1061 else if (streq(key
, "systemd.volatile")) {
1065 m
= volatile_mode_from_string(value
);
1067 log_warning_errno(m
, "Failed to parse systemd.volatile= argument: %s", value
);
1069 arg_volatile_mode
= m
;
1071 arg_volatile_mode
= VOLATILE_YES
;
1073 } else if (streq(key
, "systemd.swap")) {
1075 r
= value
? parse_boolean(value
) : 1;
1077 log_warning("Failed to parse systemd.swap switch %s. Ignoring.", value
);
1079 arg_swap_enabled
= r
;
1085 static int determine_device(char **what
, const char *hash
, const char *name
) {
1090 /* If we have a hash but no device then Verity is used, and we use the DM device. */
1097 *what
= path_join("/dev/mapper/", name
);
1101 log_info("Using verity %s device %s.", name
, *what
);
1106 static int determine_root(void) {
1107 return determine_device(&arg_root_what
, arg_root_hash
, "root");
1110 static int determine_usr(void) {
1111 return determine_device(&arg_usr_what
, arg_usr_hash
, "usr");
1114 static int run(const char *dest
, const char *dest_early
, const char *dest_late
) {
1115 int r
, r2
= 0, r3
= 0;
1117 assert_se(arg_dest
= dest
);
1118 assert_se(arg_dest_late
= dest_late
);
1120 r
= proc_cmdline_parse(parse_proc_cmdline_item
, NULL
, 0);
1122 log_warning_errno(r
, "Failed to parse kernel command line, ignoring: %m");
1124 (void) determine_root();
1125 (void) determine_usr();
1127 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
1129 r
= add_sysroot_mount();
1131 r2
= add_sysroot_usr_mount_or_fallback();
1133 r3
= add_volatile_root();
1135 r
= add_volatile_var();
1137 /* Honour /etc/fstab only when that's enabled */
1138 if (arg_fstab_enabled
) {
1139 /* Parse the local /etc/fstab, possibly from the initrd */
1140 r2
= parse_fstab(false);
1142 /* If running in the initrd also parse the /etc/fstab from the host */
1144 r3
= parse_fstab(true);
1146 r3
= generator_enable_remount_fs_service(arg_dest
);
1149 return r
< 0 ? r
: r2
< 0 ? r2
: r3
;
1152 DEFINE_MAIN_GENERATOR_FUNCTION(run
);