1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 #include "alloc-util.h"
9 #include "bus-locator.h"
10 #include "bus-unit-util.h"
12 #include "creds-util.h"
13 #include "efi-loader.h"
17 #include "fstab-util.h"
18 #include "generator.h"
19 #include "in-addr-util.h"
20 #include "initrd-util.h"
22 #include "main-func.h"
24 #include "mount-setup.h"
25 #include "mount-util.h"
26 #include "mountpoint-util.h"
27 #include "nulstr-util.h"
28 #include "parse-util.h"
29 #include "path-util.h"
30 #include "proc-cmdline.h"
31 #include "process-util.h"
33 #include "specifier.h"
34 #include "stat-util.h"
35 #include "string-util.h"
37 #include "unit-name.h"
39 #include "volatile-util.h"
41 typedef enum MountPointFlags
{
42 MOUNT_NOAUTO
= 1 << 0,
43 MOUNT_NOFAIL
= 1 << 1,
44 MOUNT_AUTOMOUNT
= 1 << 2,
45 MOUNT_MAKEFS
= 1 << 3,
46 MOUNT_GROWFS
= 1 << 4,
47 MOUNT_RW_ONLY
= 1 << 5,
51 typedef struct Mount
{
59 static void mount_array_free(Mount
*mounts
, size_t n
);
61 static bool arg_sysroot_check
= false;
62 static const char *arg_dest
= NULL
;
63 static const char *arg_dest_late
= NULL
;
64 static bool arg_fstab_enabled
= true;
65 static bool arg_swap_enabled
= true;
66 static char *arg_root_what
= NULL
;
67 static char *arg_root_fstype
= NULL
;
68 static char *arg_root_options
= NULL
;
69 static char *arg_root_hash
= NULL
;
70 static int arg_root_rw
= -1;
71 static char *arg_usr_what
= NULL
;
72 static char *arg_usr_fstype
= NULL
;
73 static char *arg_usr_options
= NULL
;
74 static char *arg_usr_hash
= NULL
;
75 static VolatileMode arg_volatile_mode
= _VOLATILE_MODE_INVALID
;
76 static bool arg_verity
= true;
77 static Mount
*arg_mounts
= NULL
;
78 static size_t arg_n_mounts
= 0;
80 STATIC_DESTRUCTOR_REGISTER(arg_root_what
, freep
);
81 STATIC_DESTRUCTOR_REGISTER(arg_root_fstype
, freep
);
82 STATIC_DESTRUCTOR_REGISTER(arg_root_options
, freep
);
83 STATIC_DESTRUCTOR_REGISTER(arg_root_hash
, freep
);
84 STATIC_DESTRUCTOR_REGISTER(arg_usr_what
, freep
);
85 STATIC_DESTRUCTOR_REGISTER(arg_usr_fstype
, freep
);
86 STATIC_DESTRUCTOR_REGISTER(arg_usr_options
, freep
);
87 STATIC_DESTRUCTOR_REGISTER(arg_usr_hash
, freep
);
88 STATIC_ARRAY_DESTRUCTOR_REGISTER(arg_mounts
, arg_n_mounts
, mount_array_free
);
90 static void mount_done(Mount
*m
) {
99 static void mount_array_free(Mount
*mounts
, size_t n
) {
100 FOREACH_ARRAY(m
, mounts
, n
)
106 static int mount_array_add_internal(
110 const char *in_fstype
,
111 const char *in_options
) {
113 _cleanup_free_
char *what
= NULL
, *where
= NULL
, *fstype
= NULL
, *options
= NULL
;
116 /* This takes what and where. */
118 what
= ASSERT_PTR(in_what
);
121 fstype
= strdup(isempty(in_fstype
) ? "auto" : in_fstype
);
125 if (streq(fstype
, "swap"))
126 where
= mfree(where
);
128 if (!isempty(in_options
)) {
129 _cleanup_strv_free_
char **options_strv
= NULL
;
131 r
= strv_split_full(&options_strv
, in_options
, ",", 0);
135 r
= strv_make_nulstr(options_strv
, &options
, NULL
);
137 r
= strv_make_nulstr(STRV_MAKE("defaults"), &options
, NULL
);
141 if (!GREEDY_REALLOC(arg_mounts
, arg_n_mounts
+ 1))
144 arg_mounts
[arg_n_mounts
++] = (Mount
) {
145 .for_initrd
= for_initrd
,
146 .what
= TAKE_PTR(what
),
147 .where
= TAKE_PTR(where
),
148 .fstype
= TAKE_PTR(fstype
),
149 .options
= TAKE_PTR(options
),
155 static int mount_array_add(bool for_initrd
, const char *str
) {
156 _cleanup_free_
char *what
= NULL
, *where
= NULL
, *fstype
= NULL
, *options
= NULL
;
161 r
= extract_many_words(&str
, ":", EXTRACT_CUNESCAPE
| EXTRACT_DONT_COALESCE_SEPARATORS
,
162 &what
, &where
, &fstype
, &options
, NULL
);
170 return mount_array_add_internal(for_initrd
, TAKE_PTR(what
), TAKE_PTR(where
), fstype
, options
);
173 static int mount_array_add_swap(bool for_initrd
, const char *str
) {
174 _cleanup_free_
char *what
= NULL
, *options
= NULL
;
179 r
= extract_many_words(&str
, ":", EXTRACT_CUNESCAPE
| EXTRACT_DONT_COALESCE_SEPARATORS
,
180 &what
, &options
, NULL
);
188 return mount_array_add_internal(for_initrd
, TAKE_PTR(what
), NULL
, "swap", options
);
191 static int write_options(FILE *f
, const char *options
) {
192 _cleanup_free_
char *o
= NULL
;
196 if (isempty(options
))
199 if (streq(options
, "defaults"))
202 o
= specifier_escape(options
);
206 fprintf(f
, "Options=%s\n", o
);
210 static int write_what(FILE *f
, const char *what
) {
211 _cleanup_free_
char *w
= NULL
;
216 w
= specifier_escape(what
);
220 fprintf(f
, "What=%s\n", w
);
228 MountPointFlags flags
) {
230 _cleanup_free_
char *name
= NULL
;
231 _cleanup_fclose_
FILE *f
= NULL
;
236 if (access("/proc/swaps", F_OK
) < 0) {
237 log_info("Swap not supported, ignoring swap entry for %s.", what
);
241 if (detect_container() > 0) {
242 log_info("Running in a container, ignoring swap entry for %s.", what
);
246 if (arg_sysroot_check
) {
247 log_info("%s should be enabled in the initrd, will request daemon-reload.", what
);
251 log_debug("Found swap entry what=%s makefs=%s growfs=%s pcrfs=%s noauto=%s nofail=%s",
253 yes_no(flags
& MOUNT_MAKEFS
), yes_no(flags
& MOUNT_GROWFS
), yes_no(flags
& MOUNT_PCRFS
),
254 yes_no(flags
& MOUNT_NOAUTO
), yes_no(flags
& MOUNT_NOFAIL
));
256 r
= unit_name_from_path(what
, ".swap", &name
);
258 return log_error_errno(r
, "Failed to generate unit name: %m");
260 r
= generator_open_unit_file(arg_dest
, source
, name
, &f
);
266 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n"
270 r
= generator_write_blockdev_dependency(f
, what
);
278 r
= write_what(f
, what
);
282 r
= write_options(f
, options
);
286 r
= fflush_and_check(f
);
288 return log_error_errno(r
, "Failed to write unit file %s: %m", name
);
290 /* use what as where, to have a nicer error message */
291 r
= generator_write_timeouts(arg_dest
, what
, what
, options
, NULL
);
295 if (flags
& MOUNT_MAKEFS
) {
296 r
= generator_hook_up_mkswap(arg_dest
, what
);
301 if (flags
& MOUNT_GROWFS
)
302 /* TODO: swap devices must be wiped and recreated */
303 log_warning("%s: growing swap devices is currently unsupported.", what
);
304 if (flags
& MOUNT_PCRFS
)
305 log_warning("%s: measuring swap devices is currently unsupported.", what
);
307 if (!(flags
& MOUNT_NOAUTO
)) {
308 r
= generator_add_symlink(arg_dest
, SPECIAL_SWAP_TARGET
,
309 (flags
& MOUNT_NOFAIL
) ? "wants" : "requires", name
);
317 static bool mount_is_network(const char *fstype
, const char *options
) {
318 return fstab_test_option(options
, "_netdev\0") ||
319 (fstype
&& fstype_is_network(fstype
));
322 static bool mount_in_initrd(const char *where
, const char *options
, bool accept_root
) {
323 return fstab_test_option(options
, "x-initrd.mount\0") ||
324 (where
&& PATH_IN_SET(where
, "/usr", accept_root
? "/" : NULL
));
327 static int write_timeout(
332 const char *unit_setting
) {
334 _cleanup_free_
char *timeout
= NULL
;
341 assert(unit_setting
);
343 r
= fstab_filter_options(opts
, filter
, NULL
, &timeout
, NULL
, NULL
);
345 return log_error_errno(r
, "Failed to parse options for '%s': %m", where
);
349 r
= parse_sec_fix_0(timeout
, &u
);
351 log_warning_errno(r
, "Failed to parse timeout '%s' for '%s', ignoring: %m", timeout
, where
);
355 fprintf(f
, "%s=%s\n", unit_setting
, FORMAT_TIMESPAN(u
, 0));
360 static int write_idle_timeout(FILE *f
, const char *where
, const char *opts
) {
361 return write_timeout(f
, where
, opts
,
362 "x-systemd.idle-timeout\0", "TimeoutIdleSec");
365 static int write_mount_timeout(FILE *f
, const char *where
, const char *opts
) {
366 return write_timeout(f
, where
, opts
,
367 "x-systemd.mount-timeout\0", "TimeoutSec");
370 static int write_dependency(
375 const char* const *unit_settings
) {
377 _cleanup_strv_free_
char **unit_names
= NULL
;
378 _cleanup_free_
char *units
= NULL
;
383 assert(unit_settings
);
385 r
= fstab_filter_options(opts
, filter
, NULL
, NULL
, &unit_names
, NULL
);
387 return log_error_errno(r
, "Failed to parse options for '%s': %m", where
);
391 STRV_FOREACH(s
, unit_names
) {
392 _cleanup_free_
char *mangled
= NULL
;
394 r
= unit_name_mangle_with_suffix(*s
, "as dependency", 0, ".mount", &mangled
);
396 return log_error_errno(r
, "Failed to generate dependency unit name for '%s': %m", where
);
398 if (!strextend_with_separator(&units
, " ", mangled
))
402 STRV_FOREACH(setting
, unit_settings
)
403 fprintf(f
, "%s=%s\n", *setting
, units
);
408 static int write_after(FILE *f
, const char *where
, const char *opts
) {
409 return write_dependency(f
, where
, opts
,
410 "x-systemd.after\0", STRV_MAKE_CONST("After"));
413 static int write_requires_after(FILE *f
, const char *where
, const char *opts
) {
414 return write_dependency(f
, where
, opts
,
415 "x-systemd.requires\0", STRV_MAKE_CONST("Requires", "After"));
418 static int write_before(FILE *f
, const char *where
, const char *opts
) {
419 return write_dependency(f
, where
, opts
,
420 "x-systemd.before\0", STRV_MAKE_CONST("Before"));
423 static int write_mounts_for(
428 const char *unit_setting
) {
430 _cleanup_strv_free_
char **paths
= NULL
, **paths_escaped
= NULL
;
436 assert(unit_setting
);
438 r
= fstab_filter_options(opts
, filter
, NULL
, NULL
, &paths
, NULL
);
440 return log_error_errno(r
, "Failed to parse options for '%s': %m", where
);
444 r
= specifier_escape_strv(paths
, &paths_escaped
);
446 return log_error_errno(r
, "Failed to escape paths for '%s': %m", where
);
448 fprintf(f
, "%s=", unit_setting
);
449 fputstrv(f
, paths_escaped
, NULL
, NULL
);
455 static int write_extra_dependencies(FILE *f
, const char *where
, const char *opts
) {
463 r
= write_after(f
, where
, opts
);
467 r
= write_requires_after(f
, where
, opts
);
471 r
= write_before(f
, where
, opts
);
475 r
= write_mounts_for(f
, where
, opts
,
476 "x-systemd.requires-mounts-for\0", "RequiresMountsFor");
480 r
= write_mounts_for(f
, where
, opts
,
481 "x-systemd.wants-mounts-for\0", "WantsMountsFor");
488 static int mandatory_mount_drop_unapplicable_options(
489 MountPointFlags
*flags
,
492 char **ret_options
) {
500 if (!(*flags
& (MOUNT_NOAUTO
|MOUNT_NOFAIL
|MOUNT_AUTOMOUNT
))) {
501 r
= strdup_or_null(options
, ret_options
);
508 log_debug("Mount '%s' is mandatory, ignoring 'noauto', 'nofail', and 'x-systemd.automount' options.",
511 *flags
&= ~(MOUNT_NOAUTO
|MOUNT_NOFAIL
|MOUNT_AUTOMOUNT
);
513 r
= fstab_filter_options(options
, "noauto\0nofail\0x-systemd.automount\0", NULL
, NULL
, NULL
, ret_options
);
520 static int add_mount(
525 const char *original_where
,
529 MountPointFlags flags
,
530 const char *target_unit
) {
532 _cleanup_free_
char *name
= NULL
, *automount_name
= NULL
, *filtered
= NULL
, *where_escaped
= NULL
,
533 *opts_root_filtered
= NULL
;
534 _cleanup_strv_free_
char **wanted_by
= NULL
, **required_by
= NULL
;
535 _cleanup_fclose_
FILE *f
= NULL
;
543 if (streq_ptr(fstype
, "autofs"))
546 if (!is_path(where
)) {
547 log_warning("Mount point %s is not a valid path, ignoring.", where
);
551 if (mount_point_is_api(where
) ||
552 mount_point_ignore(where
))
555 if (arg_sysroot_check
) {
556 log_info("%s should be mounted in the initrd, will request daemon-reload.", where
);
560 r
= fstab_filter_options(opts
, "x-systemd.wanted-by\0", NULL
, NULL
, &wanted_by
, NULL
);
564 r
= fstab_filter_options(opts
, "x-systemd.required-by\0", NULL
, NULL
, &required_by
, NULL
);
568 if (PATH_IN_SET(where
, "/", "/usr")) {
569 r
= mandatory_mount_drop_unapplicable_options(&flags
, where
, opts
, &opts_root_filtered
);
572 opts
= opts_root_filtered
;
574 if (!strv_isempty(wanted_by
))
575 log_debug("Ignoring 'x-systemd.wanted-by=' option for root/usr device.");
576 if (!strv_isempty(required_by
))
577 log_debug("Ignoring 'x-systemd.required-by=' option for root/usr device.");
579 required_by
= strv_free(required_by
);
580 wanted_by
= strv_free(wanted_by
);
583 r
= unit_name_from_path(where
, ".mount", &name
);
585 return log_error_errno(r
, "Failed to generate unit name: %m");
587 r
= generator_open_unit_file(dest
, source
, name
, &f
);
593 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n"
597 if (STRPTR_IN_SET(fstype
, "nfs", "nfs4") && !(flags
& MOUNT_AUTOMOUNT
) &&
598 fstab_test_yes_no_option(opts
, "bg\0" "fg\0")) {
599 /* The default retry timeout that mount.nfs uses for 'bg' mounts
600 * is 10000 minutes, where as it uses 2 minutes for 'fg' mounts.
601 * As we are making 'bg' mounts look like an 'fg' mount to
602 * mount.nfs (so systemd can manage the job-control aspects of 'bg'),
603 * we need to explicitly preserve that default, and also ensure
604 * the systemd mount-timeout doesn't interfere.
605 * By placing these options first, they can be overridden by
606 * settings in /etc/fstab. */
607 opts
= strjoina("x-systemd.mount-timeout=infinity,retry=10000,nofail,", opts
, ",fg");
608 SET_FLAG(flags
, MOUNT_NOFAIL
, true);
611 if (!strv_isempty(wanted_by
) || !strv_isempty(required_by
)) {
612 /* If x-systemd.{wanted,required}-by= is specified, target_unit is not used */
615 /* Don't set default ordering dependencies on local-fs.target or remote-fs.target, but we
616 * still need to conflict with umount.target. */
617 fputs("DefaultDependencies=no\n"
618 "Conflicts=umount.target\n"
619 "Before=umount.target\n",
623 r
= write_extra_dependencies(f
, where
, opts
);
627 /* Order the mount unit we generate relative to target_unit, so that DefaultDependencies= on the
628 * target unit won't affect us. */
629 if (target_unit
&& !FLAGS_SET(flags
, MOUNT_NOFAIL
))
630 fprintf(f
, "Before=%s\n", target_unit
);
633 r
= generator_write_fsck_deps(f
, dest
, what
, where
, fstype
);
638 r
= generator_write_blockdev_dependency(f
, what
);
646 r
= write_what(f
, what
);
651 fprintf(f
, "# Canonicalized from %s\n", original_where
);
653 where_escaped
= specifier_escape(where
);
656 fprintf(f
, "Where=%s\n", where_escaped
);
658 if (!isempty(fstype
) && !streq(fstype
, "auto")) {
659 _cleanup_free_
char *t
= NULL
;
661 t
= specifier_escape(fstype
);
665 fprintf(f
, "Type=%s\n", t
);
668 r
= generator_write_timeouts(dest
, what
, where
, opts
, &filtered
);
672 r
= generator_write_device_deps(dest
, what
, where
, opts
);
676 if (in_initrd() && path_equal(where
, "/sysroot") && is_device_path(what
)) {
677 r
= generator_write_initrd_root_device_deps(dest
, what
);
682 r
= write_mount_timeout(f
, where
, opts
);
686 r
= write_options(f
, filtered
);
690 if (flags
& MOUNT_RW_ONLY
)
691 fprintf(f
, "ReadWriteOnly=yes\n");
693 r
= fflush_and_check(f
);
695 return log_error_errno(r
, "Failed to write unit file %s: %m", name
);
697 if (flags
& MOUNT_MAKEFS
) {
698 r
= generator_hook_up_mkfs(dest
, what
, where
, fstype
);
703 if (flags
& MOUNT_GROWFS
) {
704 r
= generator_hook_up_growfs(dest
, where
, target_unit
);
709 if (flags
& MOUNT_PCRFS
) {
710 r
= efi_measured_uki(LOG_WARNING
);
712 log_debug("Kernel stub did not measure kernel image into PCR, skipping userspace measurement, too.");
714 r
= generator_hook_up_pcrfs(dest
, where
, target_unit
);
720 if (FLAGS_SET(flags
, MOUNT_AUTOMOUNT
)) {
721 r
= unit_name_from_path(where
, ".automount", &automount_name
);
723 return log_error_errno(r
, "Failed to generate unit name: %m");
727 r
= generator_open_unit_file(dest
, source
, automount_name
, &f
);
734 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
743 r
= write_idle_timeout(f
, where
, opts
);
747 r
= fflush_and_check(f
);
749 return log_error_errno(r
, "Failed to write unit file %s: %m", automount_name
);
753 assert(strv_isempty(wanted_by
));
754 assert(strv_isempty(required_by
));
756 /* noauto has no effect if x-systemd.automount is used */
757 if (!FLAGS_SET(flags
, MOUNT_NOAUTO
) || automount_name
) {
758 r
= generator_add_symlink(dest
, target_unit
,
759 FLAGS_SET(flags
, MOUNT_NOFAIL
) ? "wants" : "requires",
760 automount_name
?: name
);
765 const char *unit_name
= automount_name
?: name
;
767 STRV_FOREACH(s
, wanted_by
) {
768 r
= generator_add_symlink(dest
, *s
, "wants", unit_name
);
773 STRV_FOREACH(s
, required_by
) {
774 r
= generator_add_symlink(dest
, *s
, "requires", unit_name
);
779 if ((flags
& (MOUNT_NOAUTO
|MOUNT_NOFAIL
)) != 0)
780 log_warning("x-systemd.wanted-by= and/or x-systemd.required-by= specified, 'noauto' and 'nofail' have no effect.");
786 static int do_daemon_reload(void) {
787 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
788 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
791 log_debug("Calling org.freedesktop.systemd1.Manager.Reload()...");
793 r
= bus_connect_system_systemd(&bus
);
795 return log_error_errno(r
, "Failed to get D-Bus connection: %m");
797 r
= bus_service_manager_reload(bus
);
801 /* We need to requeue the two targets so that any new units which previously were not part of the
802 * targets, and which we now added, will be started. */
805 FOREACH_STRING(unit
, SPECIAL_INITRD_FS_TARGET
, SPECIAL_SWAP_TARGET
) {
806 log_info("Requesting %s/start/replace...", unit
);
808 k
= bus_call_method(bus
, bus_systemd_mgr
, "StartUnit", &error
, NULL
, "ss", unit
, "replace");
810 log_error_errno(k
, "Failed to (re)start %s: %s", unit
, bus_error_message(&error
, r
));
818 static const char* sysroot_fstab_path(void) {
819 return getenv("SYSTEMD_SYSROOT_FSTAB") ?: "/sysroot/etc/fstab";
822 static bool sysfs_check(void) {
823 static int cached
= -1;
827 r
= secure_getenv_bool("SYSTEMD_SYSFS_CHECK");
828 if (r
< 0 && r
!= -ENXIO
)
829 log_debug_errno(r
, "Failed to parse $SYSTEMD_SYSFS_CHECK, ignoring: %m");
836 static int add_sysusr_sysroot_usr_bind_mount(const char *source
) {
837 return add_mount(source
,
846 SPECIAL_INITRD_FS_TARGET
);
849 static MountPointFlags
fstab_options_to_flags(const char *options
, bool is_swap
) {
850 MountPointFlags flags
= 0;
852 if (isempty(options
))
855 if (fstab_test_option(options
, "x-systemd.makefs\0"))
856 flags
|= MOUNT_MAKEFS
;
857 if (fstab_test_option(options
, "x-systemd.growfs\0"))
858 flags
|= MOUNT_GROWFS
;
859 if (fstab_test_option(options
, "x-systemd.pcrfs\0"))
860 flags
|= MOUNT_PCRFS
;
861 if (fstab_test_yes_no_option(options
, "noauto\0" "auto\0"))
862 flags
|= MOUNT_NOAUTO
;
863 if (fstab_test_yes_no_option(options
, "nofail\0" "fail\0"))
864 flags
|= MOUNT_NOFAIL
;
867 if (fstab_test_option(options
, "x-systemd.rw-only\0"))
868 flags
|= MOUNT_RW_ONLY
;
869 if (fstab_test_option(options
,
870 "comment=systemd.automount\0"
871 "x-systemd.automount\0"))
872 flags
|= MOUNT_AUTOMOUNT
;
878 static int canonicalize_mount_path(const char *path
, const char *type
, bool prefix_sysroot
, char **ret
) {
879 _cleanup_free_
char *p
= NULL
;
885 assert(STR_IN_SET(type
, "where", "what"));
888 // FIXME: when chase() learns to chase non-existent paths, use this here and drop the prefixing with
889 // /sysroot on error below.
890 r
= chase(path
, prefix_sysroot
? "/sysroot" : NULL
, CHASE_PREFIX_ROOT
| CHASE_NONEXISTENT
, &p
, NULL
);
892 log_debug_errno(r
, "Failed to chase '%s', using as-is: %m", path
);
895 p
= path_join("/sysroot", path
);
904 changed
= !streq(path
, p
);
906 log_debug("Canonicalized %s=%s to %s", type
, path
, p
);
912 static int parse_fstab_one(
914 const char *what_original
,
915 const char *where_original
,
920 bool accept_root
, /* This takes an effect only when prefix_sysroot is true. */
921 bool use_swap_enabled
) {
923 _cleanup_free_
char *what
= NULL
, *where
= NULL
, *opts
= NULL
;
924 MountPointFlags flags
;
925 bool is_swap
, where_changed
;
928 assert(what_original
);
931 if (prefix_sysroot
&& !mount_in_initrd(where_original
, options
, accept_root
))
934 is_swap
= streq_ptr(fstype
, "swap");
935 if (is_swap
&& use_swap_enabled
&& !arg_swap_enabled
) {
936 log_info("Swap unit generation disabled on kernel command line, ignoring swap entry for %s.", what_original
);
940 what
= fstab_node_to_udev_node(what_original
);
944 if (path_is_read_only_fs("/sys") > 0 &&
945 (streq(what
, "sysfs") ||
946 (sysfs_check() && is_device_path(what
)))) {
947 log_info("/sys/ is read-only (running in a container?), ignoring mount for %s.", what
);
951 flags
= fstab_options_to_flags(options
, is_swap
);
954 return add_swap(source
, what
, options
, flags
);
957 passno
= is_device_path(what
);
959 assert(where_original
); /* 'where' is not necessary for swap entry. */
961 if (!is_path(where_original
)) {
962 log_warning("Mount point %s is not a valid path, ignoring.", where_original
);
966 /* Follow symlinks here; see 5261ba901845c084de5a8fd06500ed09bfb0bd80 which makes sense for
967 * mount units, but causes problems since it historically worked to have symlinks in e.g.
968 * /etc/fstab. So we canonicalize here. Note that we use CHASE_NONEXISTENT to handle the case
969 * where a symlink refers to another mount target; this works assuming the sub-mountpoint
970 * target is the final directory. */
971 r
= canonicalize_mount_path(where_original
, "where", prefix_sysroot
, &where
);
974 where_changed
= r
> 0;
976 if (prefix_sysroot
&& fstab_is_bind(options
, fstype
)) {
977 /* When in initrd, the source of bind mount needs to be prepended with /sysroot as well. */
978 _cleanup_free_
char *p
= NULL
;
980 r
= canonicalize_mount_path(what
, "what", prefix_sysroot
, &p
);
984 free_and_replace(what
, p
);
987 log_debug("Found entry what=%s where=%s type=%s makefs=%s growfs=%s pcrfs=%s noauto=%s nofail=%s",
988 what
, where
, strna(fstype
),
989 yes_no(flags
& MOUNT_MAKEFS
), yes_no(flags
& MOUNT_GROWFS
), yes_no(flags
& MOUNT_PCRFS
),
990 yes_no(flags
& MOUNT_NOAUTO
), yes_no(flags
& MOUNT_NOFAIL
));
992 bool is_sysroot
= in_initrd() && path_equal(where
, "/sysroot");
993 /* See comment from add_sysroot_usr_mount() about the need for extra indirection in case /usr needs
994 * to be mounted in order for the root fs to be synthesized based on configuration included in /usr/,
995 * e.g. systemd-repart. */
996 bool is_sysroot_usr
= in_initrd() && path_equal(where
, "/sysroot/usr");
998 const char *target_unit
=
999 is_sysroot
? SPECIAL_INITRD_ROOT_FS_TARGET
:
1000 is_sysroot_usr
? SPECIAL_INITRD_USR_FS_TARGET
:
1001 prefix_sysroot
? SPECIAL_INITRD_FS_TARGET
:
1002 mount_is_network(fstype
, options
) ? SPECIAL_REMOTE_FS_TARGET
:
1003 SPECIAL_LOCAL_FS_TARGET
;
1005 /* nofail, noauto and x-systemd.automount don't make sense for critical filesystems we must mount in initrd. */
1006 if (is_sysroot
|| is_sysroot_usr
) {
1007 r
= mandatory_mount_drop_unapplicable_options(&flags
, where
, options
, &opts
);
1013 r
= add_mount(source
,
1016 is_sysroot_usr
? "/sysusr/usr" : where
,
1017 !is_sysroot_usr
&& where_changed
? where_original
: NULL
,
1026 if (is_sysroot_usr
) {
1027 log_debug("Synthesizing fstab entry what=/sysusr/usr where=/sysroot/usr opts=bind");
1028 r
= add_sysusr_sysroot_usr_bind_mount(source
);
1036 static int parse_fstab(bool prefix_sysroot
) {
1037 _cleanup_endmntent_
FILE *f
= NULL
;
1043 fstab
= sysroot_fstab_path();
1045 fstab
= fstab_path();
1046 assert(!arg_sysroot_check
);
1049 log_debug("Parsing %s...", fstab
);
1051 f
= setmntent(fstab
, "re");
1053 if (errno
== ENOENT
)
1056 return log_error_errno(errno
, "Failed to open %s: %m", fstab
);
1059 while ((me
= getmntent(f
))) {
1060 r
= parse_fstab_one(fstab
,
1061 me
->mnt_fsname
, me
->mnt_dir
, me
->mnt_type
, me
->mnt_opts
, me
->mnt_passno
,
1063 /* accept_root = */ false,
1064 /* use_swap_enabled = */ true);
1065 if (r
< 0 && ret
>= 0)
1067 if (arg_sysroot_check
&& r
> 0)
1068 return true; /* We found a mount or swap that would be started… */
1074 static int sysroot_is_nfsroot(void) {
1075 union in_addr_union u
;
1076 const char *sep
, *a
;
1079 assert(arg_root_what
);
1081 /* From dracut.cmdline(7).
1083 * root=[<server-ip>:]<root-dir>[:<nfs-options>]
1084 * root=nfs:[<server-ip>:]<root-dir>[:<nfs-options>],
1085 * root=nfs4:[<server-ip>:]<root-dir>[:<nfs-options>],
1088 * mount nfs share from <server-ip>:/<root-dir>, if no server-ip is given, use dhcp next_server.
1089 * If server-ip is an IPv6 address it has to be put in brackets, e.g. [2001:DB8::1]. NFS options
1090 * can be appended with the prefix ":" or "," and are separated by ",". */
1092 if (path_equal(arg_root_what
, "/dev/nfs") ||
1093 STR_IN_SET(arg_root_what
, "dhcp", "dhcp6") ||
1094 STARTSWITH_SET(arg_root_what
, "nfs:", "nfs4:"))
1098 if (arg_root_what
[0] == '[') {
1099 sep
= strchr(arg_root_what
+ 1, ']');
1103 a
= strndupa_safe(arg_root_what
+ 1, sep
- arg_root_what
- 1);
1105 r
= in_addr_from_string(AF_INET6
, a
, &u
);
1113 sep
= strchr(arg_root_what
, ':');
1115 a
= strndupa_safe(arg_root_what
, sep
- arg_root_what
);
1117 if (in_addr_from_string(AF_INET
, a
, &u
) >= 0)
1121 /* root directory without address */
1122 return path_is_absolute(arg_root_what
) && !path_startswith(arg_root_what
, "/dev");
1125 static int add_sysroot_mount(void) {
1126 _cleanup_free_
char *what
= NULL
;
1127 const char *opts
, *fstype
;
1128 bool default_rw
, makefs
;
1129 MountPointFlags flags
;
1132 if (isempty(arg_root_what
)) {
1133 log_debug("Could not find a root= entry on the kernel command line.");
1137 if (streq(arg_root_what
, "gpt-auto")) {
1138 /* This is handled by gpt-auto-generator */
1139 log_debug("Skipping root directory handling, as gpt-auto was requested.");
1141 } else if (streq(arg_root_what
, "fstab")) {
1142 /* This is handled by parse_fstab */
1143 log_debug("Using initrd's fstab for /sysroot/ configuration.");
1147 r
= sysroot_is_nfsroot();
1149 log_debug_errno(r
, "Failed to determine if the root directory is on NFS, assuming not: %m");
1151 /* This is handled by the kernel or the initrd */
1152 log_debug("Skipping root directory handling, as root on NFS was requested.");
1156 if (startswith(arg_root_what
, "cifs://")) {
1157 log_debug("Skipping root directory handling, as root on CIFS was requested.");
1161 if (startswith(arg_root_what
, "iscsi:")) {
1162 log_debug("Skipping root directory handling, as root on iSCSI was requested.");
1166 if (startswith(arg_root_what
, "live:")) {
1167 log_debug("Skipping root directory handling, as root on live image was requested.");
1171 if (streq(arg_root_what
, "tmpfs")) {
1172 /* If root=tmpfs is specified, then take this as shortcut for a writable tmpfs mount as root */
1174 what
= strdup("rootfs"); /* just a pretty name, to show up in /proc/self/mountinfo */
1178 fstype
= arg_root_fstype
?: "tmpfs"; /* tmpfs, unless overridden */
1180 default_rw
= true; /* writable, unless overridden */;
1183 what
= fstab_node_to_udev_node(arg_root_what
);
1187 fstype
= arg_root_fstype
; /* if not specified explicitly, don't default to anything here */
1189 default_rw
= false; /* read-only, unless overridden */
1192 if (!arg_root_options
)
1193 opts
= arg_root_rw
> 0 || (arg_root_rw
< 0 && default_rw
) ? "rw" : "ro";
1194 else if (arg_root_rw
>= 0 ||
1195 !fstab_test_option(arg_root_options
, "ro\0" "rw\0"))
1196 opts
= strjoina(arg_root_options
, ",", arg_root_rw
> 0 ? "rw" : "ro");
1198 opts
= arg_root_options
;
1200 log_debug("Found entry what=%s where=/sysroot type=%s opts=%s", what
, strna(arg_root_fstype
), strempty(opts
));
1202 makefs
= fstab_test_option(opts
, "x-systemd.makefs\0");
1203 flags
= makefs
* MOUNT_MAKEFS
;
1205 return add_mount("/proc/cmdline",
1212 is_device_path(what
) ? 1 : 0, /* passno */
1213 flags
, /* makefs off, pcrfs off, noauto off, nofail off, automount off */
1214 SPECIAL_INITRD_ROOT_FS_TARGET
);
1217 static int add_sysroot_usr_mount(void) {
1218 _cleanup_free_
char *what
= NULL
;
1221 MountPointFlags flags
;
1224 /* Returns 0 if we didn't do anything, > 0 if we either generated a unit for the /usr/ mount, or we
1225 * know for sure something else did */
1227 if (!arg_usr_what
&& !arg_usr_fstype
&& !arg_usr_options
)
1230 if (arg_root_what
&& !arg_usr_what
) {
1231 /* Copy over the root device, in case the /usr mount just differs in a mount option (consider btrfs subvolumes) */
1232 arg_usr_what
= strdup(arg_root_what
);
1237 if (arg_root_fstype
&& !arg_usr_fstype
) {
1238 arg_usr_fstype
= strdup(arg_root_fstype
);
1239 if (!arg_usr_fstype
)
1243 if (arg_root_options
&& !arg_usr_options
) {
1244 arg_usr_options
= strdup(arg_root_options
);
1245 if (!arg_usr_options
)
1249 if (isempty(arg_usr_what
)) {
1250 log_debug("Could not find a mount.usr= entry on the kernel command line.");
1254 if (streq(arg_usr_what
, "gpt-auto")) {
1255 /* This is handled by the gpt-auto generator */
1256 log_debug("Skipping /usr/ directory handling, as gpt-auto was requested.");
1257 return 1; /* systemd-gpt-auto-generator will generate a unit for this, hence report that a
1258 * unit file is being created for the host /usr/ mount. */
1259 } else if (streq(arg_usr_what
, "fstab")) {
1260 /* This is handled by parse_fstab */
1261 log_debug("Using initrd's fstab for /sysroot/usr/ configuration.");
1262 return 1; /* parse_fstab will generate a unit for this, hence report that a
1263 * unit file is being created for the host /usr/ mount. */
1266 if (path_equal(arg_usr_what
, "/dev/nfs")) {
1267 /* This is handled by the initrd (if at all supported, that is) */
1268 log_debug("Skipping /usr/ directory handling, as /dev/nfs was requested.");
1269 return 1; /* As above, report that NFS code will create the unit */
1272 what
= fstab_node_to_udev_node(arg_usr_what
);
1276 if (!arg_usr_options
)
1277 opts
= arg_root_rw
> 0 ? "rw" : "ro";
1278 else if (!fstab_test_option(arg_usr_options
, "ro\0" "rw\0"))
1279 opts
= strjoina(arg_usr_options
, ",", arg_root_rw
> 0 ? "rw" : "ro");
1281 opts
= arg_usr_options
;
1283 /* When mounting /usr from the initrd, we add an extra level of indirection: we first mount the /usr/
1284 * partition to /sysusr/usr/, and then afterwards bind mount that to /sysroot/usr/. We do this so
1285 * that we can cover for systems that initially only have a /usr/ around and where the root fs needs
1286 * to be synthesized, based on configuration included in /usr/, e.g. systemd-repart. Software like
1287 * this should order itself after initrd-usr-fs.target and before initrd-fs.target; and it should
1288 * look into both /sysusr/ and /sysroot/ for the configuration data to apply. */
1290 log_debug("Found entry what=%s where=/sysusr/usr type=%s opts=%s", what
, strna(arg_usr_fstype
), strempty(opts
));
1292 makefs
= fstab_test_option(opts
, "x-systemd.makefs\0");
1293 flags
= makefs
* MOUNT_MAKEFS
;
1295 r
= add_mount("/proc/cmdline",
1302 is_device_path(what
) ? 1 : 0, /* passno */
1304 SPECIAL_INITRD_USR_FS_TARGET
);
1308 log_debug("Synthesizing entry what=/sysusr/usr where=/sysroot/usr opts=bind");
1310 r
= add_sysusr_sysroot_usr_bind_mount("/proc/cmdline");
1317 static int add_sysroot_usr_mount_or_fallback(void) {
1320 r
= add_sysroot_usr_mount();
1324 /* OK, so we didn't write anything out for /sysusr/usr/ nor /sysroot/usr/. In this case, let's make
1325 * sure that initrd-usr-fs.target is at least ordered after sysroot.mount so that services that order
1326 * themselves after it get the guarantee that /usr/ is definitely mounted somewhere. */
1328 return generator_add_symlink(
1330 SPECIAL_INITRD_USR_FS_TARGET
,
1335 static int add_volatile_root(void) {
1337 /* Let's add in systemd-remount-volatile.service which will remount the root device to tmpfs if this is
1338 * requested (or as an overlayfs), leaving only /usr from the root mount inside. */
1340 if (!IN_SET(arg_volatile_mode
, VOLATILE_YES
, VOLATILE_OVERLAY
))
1343 return generator_add_symlink(arg_dest
, SPECIAL_INITRD_ROOT_FS_TARGET
, "requires",
1344 SYSTEM_DATA_UNIT_DIR
"/" SPECIAL_VOLATILE_ROOT_SERVICE
);
1347 static int add_volatile_var(void) {
1349 if (arg_volatile_mode
!= VOLATILE_STATE
)
1352 /* If requested, mount /var as tmpfs, but do so only if there's nothing else defined for this. */
1354 return add_mount("/proc/cmdline",
1360 "mode=0755" TMPFS_LIMITS_VAR
,
1363 SPECIAL_LOCAL_FS_TARGET
);
1366 static int add_mounts_from_cmdline(void) {
1369 /* Handle each entries found in cmdline as a fstab entry. */
1371 FOREACH_ARRAY(m
, arg_mounts
, arg_n_mounts
) {
1372 if (m
->for_initrd
&& !in_initrd())
1375 RET_GATHER(r
, parse_fstab_one("/proc/cmdline",
1381 /* prefix_sysroot = */ !m
->for_initrd
&& in_initrd(),
1382 /* accept_root = */ true,
1383 /* use_swap_enabled = */ false));
1389 static int add_mounts_from_creds(bool prefix_sysroot
) {
1390 _cleanup_free_
void *b
= NULL
;
1395 assert(in_initrd() || !prefix_sysroot
);
1397 r
= read_credential_with_decryption(
1398 in_initrd() && !prefix_sysroot
? "fstab.extra.initrd" : "fstab.extra",
1403 _cleanup_fclose_
FILE *f
= NULL
;
1404 f
= fmemopen_unlocked(b
, bs
, "r");
1410 while ((me
= getmntent(f
)))
1411 RET_GATHER(r
, parse_fstab_one("/run/credentials",
1417 /* prefix_sysroot = */ prefix_sysroot
,
1418 /* accept_root = */ true,
1419 /* use_swap_enabled = */ true));
1424 static int parse_proc_cmdline_item(const char *key
, const char *value
, void *data
) {
1429 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
1430 * instance should take precedence. In the case of multiple rootflags=
1431 * or usrflags= the arguments should be concatenated */
1433 if (STR_IN_SET(key
, "fstab", "rd.fstab")) {
1435 r
= value
? parse_boolean(value
) : 1;
1437 log_warning("Failed to parse fstab switch %s. Ignoring.", value
);
1439 arg_fstab_enabled
= fstab_set_enabled(r
);
1441 } else if (streq(key
, "root")) {
1443 if (proc_cmdline_value_missing(key
, value
))
1446 return free_and_strdup_warn(&arg_root_what
, empty_to_null(value
));
1448 } else if (streq(key
, "rootfstype")) {
1450 if (proc_cmdline_value_missing(key
, value
))
1453 return free_and_strdup_warn(&arg_root_fstype
, empty_to_null(value
));
1455 } else if (streq(key
, "rootflags")) {
1457 if (proc_cmdline_value_missing(key
, value
))
1460 if (!strextend_with_separator(&arg_root_options
, ",", value
))
1463 } else if (streq(key
, "roothash")) {
1465 if (proc_cmdline_value_missing(key
, value
))
1468 return free_and_strdup_warn(&arg_root_hash
, empty_to_null(value
));
1470 } else if (streq(key
, "mount.usr")) {
1472 if (proc_cmdline_value_missing(key
, value
))
1475 return free_and_strdup_warn(&arg_usr_what
, empty_to_null(value
));
1477 } else if (streq(key
, "mount.usrfstype")) {
1479 if (proc_cmdline_value_missing(key
, value
))
1482 return free_and_strdup_warn(&arg_usr_fstype
, empty_to_null(value
));
1484 } else if (streq(key
, "mount.usrflags")) {
1486 if (proc_cmdline_value_missing(key
, value
))
1489 if (!strextend_with_separator(&arg_usr_options
, ",", value
))
1492 } else if (streq(key
, "usrhash")) {
1494 if (proc_cmdline_value_missing(key
, value
))
1497 return free_and_strdup_warn(&arg_usr_hash
, empty_to_null(value
));
1499 } else if (streq(key
, "rw") && !value
)
1501 else if (streq(key
, "ro") && !value
)
1502 arg_root_rw
= false;
1503 else if (streq(key
, "systemd.volatile")) {
1507 m
= volatile_mode_from_string(value
);
1509 log_warning_errno(m
, "Failed to parse systemd.volatile= argument: %s", value
);
1511 arg_volatile_mode
= m
;
1513 arg_volatile_mode
= VOLATILE_YES
;
1515 } else if (streq(key
, "systemd.swap")) {
1517 r
= value
? parse_boolean(value
) : 1;
1519 log_warning("Failed to parse systemd.swap switch %s. Ignoring.", value
);
1521 arg_swap_enabled
= r
;
1523 } else if (streq(key
, "systemd.verity")) {
1525 r
= value
? parse_boolean(value
) : 1;
1527 log_warning("Failed to parse systemd.verity= kernel command line switch %s. Ignoring.", value
);
1531 } else if (STR_IN_SET(key
, "systemd.mount-extra", "rd.systemd.mount-extra")) {
1533 if (proc_cmdline_value_missing(key
, value
))
1536 r
= mount_array_add(startswith(key
, "rd."), value
);
1538 log_warning("Failed to parse systemd.mount-extra= option, ignoring: %s", value
);
1540 } else if (STR_IN_SET(key
, "systemd.swap-extra", "rd.systemd.swap-extra")) {
1542 if (proc_cmdline_value_missing(key
, value
))
1545 r
= mount_array_add_swap(startswith(key
, "rd."), value
);
1547 log_warning("Failed to parse systemd.swap-extra= option, ignoring: %s", value
);
1553 static int determine_device(
1563 /* If we have a hash but no device then Verity is used, and we use the DM device. */
1573 *what
= path_join("/dev/mapper/", name
);
1577 /* Verity is always read-only */
1580 if (options
&& !strextend_with_separator(options
, ",", "ro"))
1583 log_info("Using verity %s device %s.", name
, *what
);
1587 static int determine_root(void) {
1588 return determine_device(&arg_root_what
, &arg_root_rw
, NULL
, arg_root_hash
, "root");
1591 static int determine_usr(void) {
1592 return determine_device(&arg_usr_what
, NULL
, &arg_usr_options
, arg_usr_hash
, "usr");
1595 /* If arg_sysroot_check is false, run as generator in the usual fashion.
1596 * If it is true, check /sysroot/etc/fstab for any units that we'd want to mount
1597 * in the initrd, and call daemon-reload. We will get reinvoked as a generator,
1598 * with /sysroot/etc/fstab available, and then we can write additional units based
1600 static int run_generator(void) {
1603 r
= proc_cmdline_parse(parse_proc_cmdline_item
, NULL
, 0);
1605 log_warning_errno(r
, "Failed to parse kernel command line, ignoring: %m");
1607 (void) determine_root();
1608 (void) determine_usr();
1610 if (arg_sysroot_check
) {
1611 r
= parse_fstab(/* prefix_sysroot = */ true);
1613 log_debug("Nothing interesting found, not doing daemon-reload.");
1615 r
= do_daemon_reload();
1621 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
1623 RET_GATHER(r
, add_sysroot_mount());
1625 RET_GATHER(r
, add_sysroot_usr_mount_or_fallback());
1627 RET_GATHER(r
, add_volatile_root());
1629 RET_GATHER(r
, add_volatile_var());
1631 /* Honour /etc/fstab only when that's enabled */
1632 if (arg_fstab_enabled
) {
1633 /* Parse the local /etc/fstab, possibly from the initrd */
1634 RET_GATHER(r
, parse_fstab(/* prefix_sysroot = */ false));
1636 /* If running in the initrd also parse the /etc/fstab from the host */
1638 RET_GATHER(r
, parse_fstab(/* prefix_sysroot = */ true));
1640 RET_GATHER(r
, generator_enable_remount_fs_service(arg_dest
));
1643 RET_GATHER(r
, add_mounts_from_cmdline());
1645 RET_GATHER(r
, add_mounts_from_creds(/* prefix_sysroot = */ false));
1648 RET_GATHER(r
, add_mounts_from_creds(/* prefix_sysroot = */ true));
1653 static int run(int argc
, char **argv
) {
1654 arg_sysroot_check
= invoked_as(argv
, "systemd-sysroot-fstab-check");
1656 if (arg_sysroot_check
) {
1657 /* Run as in systemd-sysroot-fstab-check mode */
1660 if (strv_length(argv
) > 1)
1661 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1662 "This program takes no arguments.");
1664 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1665 "This program is only useful in the initrd.");
1667 /* Run in generator mode */
1668 log_setup_generator();
1670 if (!IN_SET(strv_length(argv
), 2, 4))
1671 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1672 "This program takes one or three arguments.");
1674 arg_dest
= ASSERT_PTR(argv
[1]);
1675 arg_dest_late
= ASSERT_PTR(argv
[argc
> 3 ? 3 : 1]);
1678 return run_generator();
1681 DEFINE_MAIN_FUNCTION(run
);