1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
9 #include "alloc-util.h"
10 #include "argv-util.h"
11 #include "bus-error.h"
12 #include "bus-locator.h"
13 #include "bus-unit-util.h"
16 #include "creds-util.h"
17 #include "efi-loader.h"
19 #include "errno-util.h"
20 #include "extract-word.h"
23 #include "fstab-util.h"
24 #include "generator.h"
25 #include "in-addr-util.h"
26 #include "initrd-util.h"
28 #include "main-func.h"
29 #include "mount-setup.h"
30 #include "mount-util.h"
31 #include "mountpoint-util.h"
32 #include "parse-util.h"
33 #include "path-util.h"
34 #include "proc-cmdline.h"
36 #include "specifier.h"
37 #include "stat-util.h"
38 #include "string-util.h"
40 #include "unit-name.h"
42 #include "volatile-util.h"
44 typedef enum MountPointFlags
{
45 MOUNT_NOAUTO
= 1 << 0,
46 MOUNT_NOFAIL
= 1 << 1,
47 MOUNT_AUTOMOUNT
= 1 << 2,
48 MOUNT_MAKEFS
= 1 << 3,
49 MOUNT_GROWFS
= 1 << 4,
50 MOUNT_RW_ONLY
= 1 << 5,
53 MOUNT_VALIDATEFS
= 1 << 8,
56 typedef struct Mount
{
64 static void mount_array_free(Mount
*mounts
, size_t n
);
66 static bool arg_sysroot_check
= false;
67 static const char *arg_dest
= NULL
;
68 static const char *arg_dest_late
= NULL
;
69 static bool arg_fstab_enabled
= true;
70 static bool arg_swap_enabled
= true;
71 static char *arg_root_what
= NULL
;
72 static char *arg_root_fstype
= NULL
;
73 static char *arg_root_options
= NULL
;
74 static char *arg_root_hash
= NULL
;
75 static int arg_root_rw
= -1;
76 static char *arg_usr_what
= NULL
;
77 static char *arg_usr_fstype
= NULL
;
78 static char *arg_usr_options
= NULL
;
79 static char *arg_usr_hash
= NULL
;
80 static VolatileMode arg_volatile_mode
= _VOLATILE_MODE_INVALID
;
81 static bool arg_verity
= true;
82 static Mount
*arg_mounts
= NULL
;
83 static size_t arg_n_mounts
= 0;
85 STATIC_DESTRUCTOR_REGISTER(arg_root_what
, freep
);
86 STATIC_DESTRUCTOR_REGISTER(arg_root_fstype
, freep
);
87 STATIC_DESTRUCTOR_REGISTER(arg_root_options
, freep
);
88 STATIC_DESTRUCTOR_REGISTER(arg_root_hash
, freep
);
89 STATIC_DESTRUCTOR_REGISTER(arg_usr_what
, freep
);
90 STATIC_DESTRUCTOR_REGISTER(arg_usr_fstype
, freep
);
91 STATIC_DESTRUCTOR_REGISTER(arg_usr_options
, freep
);
92 STATIC_DESTRUCTOR_REGISTER(arg_usr_hash
, freep
);
93 STATIC_ARRAY_DESTRUCTOR_REGISTER(arg_mounts
, arg_n_mounts
, mount_array_free
);
95 static void mount_done(Mount
*m
) {
104 static void mount_array_free(Mount
*mounts
, size_t n
) {
105 FOREACH_ARRAY(m
, mounts
, n
)
111 static int mount_array_add_internal(
115 const char *in_fstype
,
118 _cleanup_free_
char *what
= NULL
, *where
= NULL
, *fstype
= NULL
, *options
= NULL
;
120 /* This takes what and where. */
122 what
= ASSERT_PTR(in_what
);
124 options
= in_options
;
126 fstype
= strdup(isempty(in_fstype
) ? "auto" : in_fstype
);
130 if (streq(fstype
, "swap"))
131 where
= mfree(where
);
133 if (!GREEDY_REALLOC(arg_mounts
, arg_n_mounts
+ 1))
136 arg_mounts
[arg_n_mounts
++] = (Mount
) {
137 .for_initrd
= for_initrd
,
138 .what
= TAKE_PTR(what
),
139 .where
= TAKE_PTR(where
),
140 .fstype
= TAKE_PTR(fstype
),
141 .options
= TAKE_PTR(options
),
147 static int mount_array_add(bool for_initrd
, const char *str
) {
148 _cleanup_free_
char *what
= NULL
, *where
= NULL
, *fstype
= NULL
, *options
= NULL
;
153 r
= extract_many_words(&str
, ":", EXTRACT_CUNESCAPE
| EXTRACT_DONT_COALESCE_SEPARATORS
,
154 &what
, &where
, &fstype
, &options
);
162 return mount_array_add_internal(for_initrd
, TAKE_PTR(what
), TAKE_PTR(where
), fstype
, TAKE_PTR(options
));
165 static int mount_array_add_swap(bool for_initrd
, const char *str
) {
166 _cleanup_free_
char *what
= NULL
, *options
= NULL
;
171 r
= extract_many_words(&str
, ":", EXTRACT_CUNESCAPE
| EXTRACT_DONT_COALESCE_SEPARATORS
,
180 return mount_array_add_internal(for_initrd
, TAKE_PTR(what
), NULL
, "swap", TAKE_PTR(options
));
183 static int write_options(FILE *f
, const char *options
) {
184 _cleanup_free_
char *o
= NULL
;
188 if (isempty(options
))
191 if (streq(options
, "defaults"))
194 o
= specifier_escape(options
);
198 fprintf(f
, "Options=%s\n", o
);
202 static int write_what(FILE *f
, const char *what
) {
203 _cleanup_free_
char *w
= NULL
;
208 w
= specifier_escape(what
);
212 fprintf(f
, "What=%s\n", w
);
220 MountPointFlags flags
) {
222 _cleanup_free_
char *name
= NULL
;
223 _cleanup_fclose_
FILE *f
= NULL
;
228 if (access("/proc/swaps", F_OK
) < 0) {
229 log_info("Swap not supported, ignoring swap entry for %s.", what
);
233 if (detect_container() > 0) {
234 log_info("Running in a container, ignoring swap entry for %s.", what
);
238 if (arg_sysroot_check
) {
239 log_info("%s should be enabled in the initrd, will request daemon-reload.", what
);
243 log_debug("Found swap entry what=%s makefs=%s growfs=%s pcrfs=%s validatefs=%s noauto=%s nofail=%s",
245 yes_no(flags
& MOUNT_MAKEFS
), yes_no(flags
& MOUNT_GROWFS
),
246 yes_no(flags
& MOUNT_PCRFS
), yes_no(flags
& MOUNT_VALIDATEFS
),
247 yes_no(flags
& MOUNT_NOAUTO
), yes_no(flags
& MOUNT_NOFAIL
));
249 r
= unit_name_from_path(what
, ".swap", &name
);
251 return log_error_errno(r
, "Failed to generate unit name: %m");
253 r
= generator_open_unit_file(arg_dest
, source
, name
, &f
);
259 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n"
263 r
= generator_write_blockdev_dependency(f
, what
);
271 r
= write_what(f
, what
);
275 r
= write_options(f
, options
);
279 r
= fflush_and_check(f
);
281 return log_error_errno(r
, "Failed to write unit file %s: %m", name
);
283 /* use what as where, to have a nicer error message */
284 r
= generator_write_device_timeout(arg_dest
, what
, options
, NULL
);
288 if (flags
& MOUNT_MAKEFS
) {
289 r
= generator_hook_up_mkswap(arg_dest
, what
);
294 if (flags
& MOUNT_GROWFS
)
295 /* TODO: swap devices must be wiped and recreated */
296 log_warning("%s: growing swap devices is currently unsupported.", what
);
297 if (flags
& MOUNT_PCRFS
)
298 log_warning("%s: measuring swap devices is currently unsupported.", what
);
299 if (flags
& MOUNT_VALIDATEFS
)
300 log_warning("%s: validating swap devices is currently unsupported.", what
);
302 if (!(flags
& MOUNT_NOAUTO
)) {
303 r
= generator_add_symlink(arg_dest
, SPECIAL_SWAP_TARGET
,
304 (flags
& MOUNT_NOFAIL
) ? "wants" : "requires", name
);
312 static bool mount_is_network(const char *fstype
, const char *options
) {
313 return fstab_test_option(options
, "_netdev\0") ||
314 (fstype
&& fstype_is_network(fstype
));
317 static bool mount_in_initrd(const char *where
, const char *options
, bool accept_root
) {
318 return fstab_test_option(options
, "x-initrd.mount\0") ||
319 (where
&& PATH_IN_SET(where
, "/usr", accept_root
? "/" : NULL
));
322 static int write_idle_timeout(FILE *f
, const char *where
, const char *opts
) {
323 return generator_write_unit_timeout(f
, where
, opts
,
324 "x-systemd.idle-timeout\0", "TimeoutIdleSec");
327 static int write_dependency(
332 const char* const *unit_settings
) {
334 _cleanup_strv_free_
char **unit_names
= NULL
;
335 _cleanup_free_
char *units
= NULL
;
340 assert(unit_settings
);
342 r
= fstab_filter_options(opts
, filter
, NULL
, NULL
, &unit_names
, NULL
);
344 return log_error_errno(r
, "Failed to parse options for '%s': %m", where
);
348 STRV_FOREACH(s
, unit_names
) {
349 _cleanup_free_
char *mangled
= NULL
;
351 r
= unit_name_mangle_with_suffix(*s
, "as dependency", 0, ".mount", &mangled
);
353 return log_error_errno(r
, "Failed to generate dependency unit name for '%s': %m", where
);
355 if (!strextend_with_separator(&units
, " ", mangled
))
359 STRV_FOREACH(setting
, unit_settings
)
360 fprintf(f
, "%s=%s\n", *setting
, units
);
365 static int write_after(FILE *f
, const char *where
, const char *opts
) {
366 return write_dependency(f
, where
, opts
,
367 "x-systemd.after\0", STRV_MAKE_CONST("After"));
370 static int write_requires_after(FILE *f
, const char *where
, const char *opts
) {
371 return write_dependency(f
, where
, opts
,
372 "x-systemd.requires\0", STRV_MAKE_CONST("Requires", "After"));
375 static int write_wants_after(FILE *f
, const char *where
, const char *opts
) {
376 return write_dependency(f
, where
, opts
,
377 "x-systemd.wants\0", STRV_MAKE_CONST("Wants", "After"));
380 static int write_before(FILE *f
, const char *where
, const char *opts
) {
381 return write_dependency(f
, where
, opts
,
382 "x-systemd.before\0", STRV_MAKE_CONST("Before"));
385 static int write_mounts_for(
390 const char *unit_setting
) {
392 _cleanup_strv_free_
char **paths
= NULL
, **paths_escaped
= NULL
;
398 assert(unit_setting
);
400 r
= fstab_filter_options(opts
, filter
, NULL
, NULL
, &paths
, NULL
);
402 return log_error_errno(r
, "Failed to parse options for '%s': %m", where
);
406 r
= specifier_escape_strv(paths
, &paths_escaped
);
408 return log_error_errno(r
, "Failed to escape paths for '%s': %m", where
);
410 fprintf(f
, "%s=", unit_setting
);
411 fputstrv(f
, paths_escaped
, NULL
, NULL
);
417 static int write_extra_dependencies(FILE *f
, const char *where
, const char *opts
) {
425 r
= write_after(f
, where
, opts
);
429 r
= write_requires_after(f
, where
, opts
);
433 r
= write_wants_after(f
, where
, opts
);
437 r
= write_before(f
, where
, opts
);
441 r
= write_mounts_for(f
, where
, opts
,
442 "x-systemd.requires-mounts-for\0", "RequiresMountsFor");
446 r
= write_mounts_for(f
, where
, opts
,
447 "x-systemd.wants-mounts-for\0", "WantsMountsFor");
454 static int mandatory_mount_drop_unapplicable_options(
455 MountPointFlags
*flags
,
458 char **ret_options
) {
466 if (!(*flags
& (MOUNT_NOAUTO
|MOUNT_NOFAIL
|MOUNT_AUTOMOUNT
)))
467 return strdup_to(ret_options
, options
);
469 log_debug("Mount '%s' is mandatory, ignoring 'noauto', 'nofail', and 'x-systemd.automount' options.",
472 *flags
&= ~(MOUNT_NOAUTO
|MOUNT_NOFAIL
|MOUNT_AUTOMOUNT
);
474 r
= fstab_filter_options(options
, "noauto\0nofail\0x-systemd.automount\0", NULL
, NULL
, NULL
, ret_options
);
481 static int add_mount(
486 const char *original_where
,
490 MountPointFlags flags
,
491 const char *target_unit
,
492 const char *extra_after
) {
494 _cleanup_free_
char *name
= NULL
, *automount_name
= NULL
, *filtered
= NULL
, *where_escaped
= NULL
,
495 *opts_root_filtered
= NULL
;
496 _cleanup_strv_free_
char **wanted_by
= NULL
, **required_by
= NULL
;
497 _cleanup_fclose_
FILE *f
= NULL
;
505 if (streq_ptr(fstype
, "autofs"))
508 if (!is_path(where
)) {
509 log_warning("Mount point %s is not a valid path, ignoring.", where
);
513 if (mount_point_is_api(where
) ||
514 mount_point_ignore(where
))
517 if (arg_sysroot_check
) {
518 log_info("%s should be mounted in the initrd, will request daemon-reload.", where
);
522 r
= fstab_filter_options(opts
, "x-systemd.wanted-by\0", NULL
, NULL
, &wanted_by
, NULL
);
526 r
= fstab_filter_options(opts
, "x-systemd.required-by\0", NULL
, NULL
, &required_by
, NULL
);
530 if (PATH_IN_SET(where
, "/", "/usr")) {
531 r
= mandatory_mount_drop_unapplicable_options(&flags
, where
, opts
, &opts_root_filtered
);
534 opts
= opts_root_filtered
;
536 if (!strv_isempty(wanted_by
))
537 log_debug("Ignoring 'x-systemd.wanted-by=' option for root/usr device.");
538 if (!strv_isempty(required_by
))
539 log_debug("Ignoring 'x-systemd.required-by=' option for root/usr device.");
541 required_by
= strv_free(required_by
);
542 wanted_by
= strv_free(wanted_by
);
545 r
= unit_name_from_path(where
, ".mount", &name
);
547 return log_error_errno(r
, "Failed to generate unit name: %m");
549 r
= generator_open_unit_file(dest
, source
, name
, &f
);
555 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n"
559 if (STRPTR_IN_SET(fstype
, "nfs", "nfs4") && !(flags
& MOUNT_AUTOMOUNT
) &&
560 fstab_test_yes_no_option(opts
, "bg\0" "fg\0")) {
561 /* The default retry timeout that mount.nfs uses for 'bg' mounts
562 * is 10000 minutes, where as it uses 2 minutes for 'fg' mounts.
563 * As we are making 'bg' mounts look like an 'fg' mount to
564 * mount.nfs (so systemd can manage the job-control aspects of 'bg'),
565 * we need to explicitly preserve that default, and also ensure
566 * the systemd mount-timeout doesn't interfere.
567 * By placing these options first, they can be overridden by
568 * settings in /etc/fstab. */
569 opts
= strjoina("x-systemd.mount-timeout=infinity,retry=10000,nofail,", opts
, ",fg");
570 SET_FLAG(flags
, MOUNT_NOFAIL
, true);
573 if (!strv_isempty(wanted_by
) || !strv_isempty(required_by
)) {
574 /* If x-systemd.{wanted,required}-by= is specified, target_unit is not used */
577 /* Don't set default ordering dependencies on local-fs.target or remote-fs.target, but we
578 * still need to conflict with umount.target. */
579 fputs("DefaultDependencies=no\n"
580 "Conflicts=umount.target\n"
581 "Before=umount.target\n",
585 r
= write_extra_dependencies(f
, where
, opts
);
589 /* Order the mount unit we generate relative to target_unit, so that DefaultDependencies= on the
590 * target unit won't affect us. */
591 if (target_unit
&& !FLAGS_SET(flags
, MOUNT_NOFAIL
))
592 fprintf(f
, "Before=%s\n", target_unit
);
595 fprintf(f
, "After=%s\n", extra_after
);
598 r
= generator_write_fsck_deps(f
, dest
, what
, where
, fstype
, opts
);
603 r
= generator_write_blockdev_dependency(f
, what
);
611 r
= write_what(f
, what
);
616 fprintf(f
, "# Canonicalized from %s\n", original_where
);
618 where_escaped
= specifier_escape(where
);
621 fprintf(f
, "Where=%s\n", where_escaped
);
623 if (!isempty(fstype
) && !streq(fstype
, "auto")) {
624 _cleanup_free_
char *t
= NULL
;
626 t
= specifier_escape(fstype
);
630 fprintf(f
, "Type=%s\n", t
);
633 r
= generator_write_device_timeout(dest
, what
, opts
, &filtered
);
637 r
= generator_write_network_device_deps(dest
, what
, where
, opts
);
641 if (in_initrd() && path_equal(where
, "/sysroot") && is_device_path(what
)) {
642 r
= generator_write_initrd_root_device_deps(dest
, what
);
647 r
= generator_write_mount_timeout(f
, where
, opts
);
651 r
= write_options(f
, filtered
);
655 if (flags
& MOUNT_RW_ONLY
)
656 fprintf(f
, "ReadWriteOnly=yes\n");
658 r
= fflush_and_check(f
);
660 return log_error_errno(r
, "Failed to write unit file %s: %m", name
);
662 if (flags
& MOUNT_MAKEFS
) {
663 r
= generator_hook_up_mkfs(dest
, what
, where
, fstype
);
668 if (flags
& MOUNT_GROWFS
) {
669 r
= generator_hook_up_growfs(dest
, where
, target_unit
);
674 if (flags
& MOUNT_PCRFS
) {
675 r
= efi_measured_uki(LOG_WARNING
);
677 log_debug("Kernel stub did not measure kernel image into PCR, skipping userspace measurement, too.");
679 r
= generator_hook_up_pcrfs(dest
, where
, target_unit
);
685 if (flags
& MOUNT_VALIDATEFS
) {
686 r
= generator_hook_up_validatefs(dest
, where
, target_unit
);
691 if (flags
& MOUNT_QUOTA
) {
692 r
= generator_hook_up_quotacheck(dest
, what
, where
, target_unit
, fstype
);
694 if (r
!= -EOPNOTSUPP
)
697 r
= generator_hook_up_quotaon(dest
, where
, target_unit
);
703 if (FLAGS_SET(flags
, MOUNT_AUTOMOUNT
)) {
704 r
= unit_name_from_path(where
, ".automount", &automount_name
);
706 return log_error_errno(r
, "Failed to generate unit name: %m");
710 r
= generator_open_unit_file(dest
, source
, automount_name
, &f
);
717 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
726 r
= write_idle_timeout(f
, where
, opts
);
730 r
= fflush_and_check(f
);
732 return log_error_errno(r
, "Failed to write unit file %s: %m", automount_name
);
736 assert(strv_isempty(wanted_by
));
737 assert(strv_isempty(required_by
));
739 /* noauto has no effect if x-systemd.automount is used */
740 if (!FLAGS_SET(flags
, MOUNT_NOAUTO
) || automount_name
) {
741 r
= generator_add_symlink(dest
, target_unit
,
742 FLAGS_SET(flags
, MOUNT_NOFAIL
) ? "wants" : "requires",
743 automount_name
?: name
);
748 const char *unit_name
= automount_name
?: name
;
750 STRV_FOREACH(s
, wanted_by
) {
751 r
= generator_add_symlink(dest
, *s
, "wants", unit_name
);
756 STRV_FOREACH(s
, required_by
) {
757 r
= generator_add_symlink(dest
, *s
, "requires", unit_name
);
762 if ((flags
& (MOUNT_NOAUTO
|MOUNT_NOFAIL
)) != 0)
763 log_warning("x-systemd.wanted-by= and/or x-systemd.required-by= specified, 'noauto' and 'nofail' have no effect.");
769 static int do_daemon_reload(void) {
770 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
771 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
774 log_debug("Calling org.freedesktop.systemd1.Manager.Reload()...");
776 r
= bus_connect_system_systemd(&bus
);
778 return log_error_errno(r
, "Failed to get D-Bus connection: %m");
780 r
= bus_service_manager_reload(bus
);
784 /* We need to requeue the two targets so that any new units which previously were not part of the
785 * targets, and which we now added, will be started. */
788 FOREACH_STRING(unit
, SPECIAL_INITRD_FS_TARGET
, SPECIAL_SWAP_TARGET
) {
789 log_info("Requesting %s/start/replace...", unit
);
791 k
= bus_call_method(bus
, bus_systemd_mgr
, "StartUnit", &error
, NULL
, "ss", unit
, "replace");
793 log_error_errno(k
, "Failed to (re)start %s: %s", unit
, bus_error_message(&error
, r
));
801 static const char* sysroot_fstab_path(void) {
802 return getenv("SYSTEMD_SYSROOT_FSTAB") ?: "/sysroot/etc/fstab";
805 static bool sysfs_check(void) {
806 static int cached
= -1;
810 r
= secure_getenv_bool("SYSTEMD_SYSFS_CHECK");
811 if (r
< 0 && r
!= -ENXIO
)
812 log_debug_errno(r
, "Failed to parse $SYSTEMD_SYSFS_CHECK, ignoring: %m");
819 static int add_sysusr_sysroot_usr_bind_mount(const char *source
, bool validatefs
) {
820 log_debug("Synthesizing entry what=/sysusr/usr where=/sysroot/usr opts=bind validatefs=%s", yes_no(validatefs
));
822 return add_mount(source
,
826 /* original_where= */ NULL
,
830 validatefs
? MOUNT_VALIDATEFS
: 0,
831 SPECIAL_INITRD_FS_TARGET
,
832 /* extra_after= */ NULL
);
835 static MountPointFlags
fstab_options_to_flags(const char *options
, bool is_swap
) {
836 MountPointFlags flags
= 0;
838 if (isempty(options
))
841 if (fstab_test_option(options
, "x-systemd.makefs\0"))
842 flags
|= MOUNT_MAKEFS
;
843 if (fstab_test_option(options
, "x-systemd.growfs\0"))
844 flags
|= MOUNT_GROWFS
;
845 if (fstab_test_option(options
, "x-systemd.pcrfs\0"))
846 flags
|= MOUNT_PCRFS
;
847 if (fstab_test_option(options
, "x-systemd.validatefs\0"))
848 flags
|= MOUNT_VALIDATEFS
;
849 if (fstab_test_option(options
, "usrquota\0" "grpquota\0" "quota\0" "usrjquota\0" "grpjquota\0" "prjquota\0"))
850 flags
|= MOUNT_QUOTA
;
851 if (fstab_test_yes_no_option(options
, "noauto\0" "auto\0"))
852 flags
|= MOUNT_NOAUTO
;
853 if (fstab_test_yes_no_option(options
, "nofail\0" "fail\0"))
854 flags
|= MOUNT_NOFAIL
;
857 if (fstab_test_option(options
, "x-systemd.rw-only\0"))
858 flags
|= MOUNT_RW_ONLY
;
859 if (fstab_test_option(options
,
860 "comment=systemd.automount\0"
861 "x-systemd.automount\0"))
862 flags
|= MOUNT_AUTOMOUNT
;
868 static int canonicalize_mount_path(const char *path
, const char *type
, bool prefix_sysroot
, char **ret
) {
869 _cleanup_free_
char *p
= NULL
;
875 assert(STR_IN_SET(type
, "where", "what"));
878 // FIXME: when chase() learns to chase non-existent paths, use this here and drop the prefixing with
879 // /sysroot on error below.
880 r
= chase(path
, prefix_sysroot
? "/sysroot" : NULL
, CHASE_PREFIX_ROOT
| CHASE_NONEXISTENT
, &p
, NULL
);
882 log_debug_errno(r
, "Failed to chase '%s', using as-is: %m", path
);
885 p
= path_join("/sysroot", path
);
894 changed
= !streq(path
, p
);
896 log_debug("Canonicalized %s=%s to %s", type
, path
, p
);
902 static int parse_fstab_one(
904 const char *what_original
,
905 const char *where_original
,
910 bool accept_root
, /* This takes an effect only when prefix_sysroot is true. */
911 bool use_swap_enabled
) {
913 _cleanup_free_
char *what
= NULL
, *where
= NULL
, *opts
= NULL
;
914 MountPointFlags flags
;
915 bool is_swap
, where_changed
;
918 assert(what_original
);
921 if (prefix_sysroot
&& !mount_in_initrd(where_original
, options
, accept_root
))
924 is_swap
= streq_ptr(fstype
, "swap");
925 if (is_swap
&& use_swap_enabled
&& !arg_swap_enabled
) {
926 log_info("Swap unit generation disabled on kernel command line, ignoring swap entry for %s.", what_original
);
930 what
= fstab_node_to_udev_node(what_original
);
934 if (path_is_read_only_fs("/sys") > 0 &&
935 (streq(what
, "sysfs") ||
936 (sysfs_check() && is_device_path(what
)))) {
937 log_info("/sys/ is read-only (running in a container?), ignoring mount for %s.", what
);
941 flags
= fstab_options_to_flags(options
, is_swap
);
944 return add_swap(source
, what
, options
, flags
);
947 passno
= is_device_path(what
);
949 assert(where_original
); /* 'where' is not necessary for swap entry. */
951 if (!is_path(where_original
)) {
952 log_warning("Mount point %s is not a valid path, ignoring.", where_original
);
956 /* Follow symlinks here; see 5261ba901845c084de5a8fd06500ed09bfb0bd80 which makes sense for
957 * mount units, but causes problems since it historically worked to have symlinks in e.g.
958 * /etc/fstab. So we canonicalize here. Note that we use CHASE_NONEXISTENT to handle the case
959 * where a symlink refers to another mount target; this works assuming the sub-mountpoint
960 * target is the final directory. */
961 r
= canonicalize_mount_path(where_original
, "where", prefix_sysroot
, &where
);
964 where_changed
= r
> 0;
966 if (prefix_sysroot
&& fstab_is_bind(options
, fstype
)) {
967 /* When in initrd, the source of bind mount needs to be prepended with /sysroot as well. */
968 _cleanup_free_
char *p
= NULL
;
970 r
= canonicalize_mount_path(what
, "what", prefix_sysroot
, &p
);
974 free_and_replace(what
, p
);
977 log_debug("Found entry what=%s where=%s type=%s makefs=%s growfs=%s pcrfs=%s validatefs=%s noauto=%s nofail=%s",
978 what
, where
, strna(fstype
),
979 yes_no(flags
& MOUNT_MAKEFS
), yes_no(flags
& MOUNT_GROWFS
),
980 yes_no(flags
& MOUNT_PCRFS
), yes_no(flags
& MOUNT_VALIDATEFS
),
981 yes_no(flags
& MOUNT_NOAUTO
), yes_no(flags
& MOUNT_NOFAIL
));
983 bool is_sysroot
= in_initrd() && path_equal(where
, "/sysroot");
984 /* See comment from add_sysroot_usr_mount() about the need for extra indirection in case /usr needs
985 * to be mounted in order for the root fs to be synthesized based on configuration included in /usr/,
986 * e.g. systemd-repart. */
987 bool is_sysroot_usr
= in_initrd() && path_equal(where
, "/sysroot/usr");
989 const char *target_unit
=
990 is_sysroot
? SPECIAL_INITRD_ROOT_FS_TARGET
:
991 is_sysroot_usr
? SPECIAL_INITRD_USR_FS_TARGET
:
992 prefix_sysroot
? SPECIAL_INITRD_FS_TARGET
:
993 mount_is_network(fstype
, options
) ? SPECIAL_REMOTE_FS_TARGET
:
994 SPECIAL_LOCAL_FS_TARGET
;
996 /* nofail, noauto and x-systemd.automount don't make sense for critical filesystems we must mount in initrd. */
997 if (is_sysroot
|| is_sysroot_usr
) {
998 r
= mandatory_mount_drop_unapplicable_options(&flags
, where
, options
, &opts
);
1004 r
= add_mount(source
,
1007 is_sysroot_usr
? "/sysusr/usr" : where
,
1008 !is_sysroot_usr
&& where_changed
? where_original
: NULL
,
1012 flags
& ~(is_sysroot_usr
? MOUNT_VALIDATEFS
: 0),
1014 /* extra_after= */ NULL
);
1018 if (is_sysroot_usr
) {
1019 r
= add_sysusr_sysroot_usr_bind_mount(source
, flags
& MOUNT_VALIDATEFS
);
1027 static int parse_fstab(bool prefix_sysroot
) {
1028 _cleanup_endmntent_
FILE *f
= NULL
;
1034 fstab
= sysroot_fstab_path();
1036 fstab
= fstab_path();
1037 assert(!arg_sysroot_check
);
1040 log_debug("Parsing %s...", fstab
);
1042 f
= setmntent(fstab
, "re");
1044 if (errno
== ENOENT
)
1047 return log_error_errno(errno
, "Failed to open %s: %m", fstab
);
1050 while ((me
= getmntent(f
))) {
1051 r
= parse_fstab_one(fstab
,
1052 me
->mnt_fsname
, me
->mnt_dir
, me
->mnt_type
, me
->mnt_opts
, me
->mnt_passno
,
1054 /* accept_root = */ false,
1055 /* use_swap_enabled = */ true);
1056 if (r
< 0 && ret
>= 0)
1058 if (arg_sysroot_check
&& r
> 0)
1059 return true; /* We found a mount or swap that would be started… */
1065 static int mount_source_is_nfsroot(const char *what
) {
1066 union in_addr_union u
;
1067 const char *sep
, *a
;
1072 /* From dracut.cmdline(7).
1074 * root=[<server-ip>:]<root-dir>[:<nfs-options>]
1075 * root=nfs:[<server-ip>:]<root-dir>[:<nfs-options>],
1076 * root=nfs4:[<server-ip>:]<root-dir>[:<nfs-options>],
1079 * mount nfs share from <server-ip>:/<root-dir>, if no server-ip is given, use dhcp next_server.
1080 * If server-ip is an IPv6 address it has to be put in brackets, e.g. [2001:DB8::1]. NFS options
1081 * can be appended with the prefix ":" or "," and are separated by ",". */
1083 if (path_equal(what
, "/dev/nfs") ||
1084 STR_IN_SET(what
, "dhcp", "dhcp6") ||
1085 STARTSWITH_SET(what
, "nfs:", "nfs4:"))
1089 if (what
[0] == '[') {
1090 sep
= strchr(what
+ 1, ']');
1094 a
= strndupa_safe(what
+ 1, sep
- what
- 1);
1096 r
= in_addr_from_string(AF_INET6
, a
, &u
);
1104 sep
= strchr(what
, ':');
1106 a
= strndupa_safe(what
, sep
- what
);
1108 if (in_addr_from_string(AF_INET
, a
, &u
) >= 0)
1112 /* root directory without address */
1113 return path_is_absolute(what
) && !path_startswith(what
, "/dev");
1116 static bool validate_root_or_usr_mount_source(const char *what
, const char *switch_name
) {
1119 assert(switch_name
);
1121 if (isempty(what
)) {
1122 log_debug("No %s switch specified on the kernel command line.", switch_name
);
1126 if (streq(what
, "off")) {
1127 log_debug("Skipping %s directory handling, as this was explicitly turned off.", switch_name
);
1131 if (parse_gpt_auto_root(switch_name
, what
) > 0) {
1132 /* This is handled by gpt-auto-generator */
1133 log_debug("Skipping %s directory handling, as gpt-auto was requested.", switch_name
);
1137 if (streq(what
, "fstab")) {
1138 /* This is handled by parse_fstab() */
1139 log_debug("Using initrd's fstab for %s configuration.", switch_name
);
1143 r
= mount_source_is_nfsroot(what
);
1145 log_debug_errno(r
, "Failed to determine if the %s directory is on NFS, assuming not: %m", switch_name
);
1147 /* This is handled by the kernel or the initrd */
1148 log_debug("Skipping %s directory handling, as root on NFS was requested.", switch_name
);
1152 if (startswith(what
, "cifs://")) {
1153 log_debug("Skipping %s directory handling, as root on CIFS was requested.", switch_name
);
1157 if (startswith(what
, "iscsi:")) {
1158 log_debug("Skipping %s directory handling, as root on iSCSI was requested.", switch_name
);
1162 if (startswith(what
, "live:")) {
1163 log_debug("Skipping %s directory handling, as root on live image was requested.", switch_name
);
1170 static int add_sysroot_mount(void) {
1171 _cleanup_free_
char *what
= NULL
;
1172 const char *extra_opts
= NULL
, *fstype
= NULL
;
1173 bool default_rw
= true;
1174 MountPointFlags flags
;
1176 if (!validate_root_or_usr_mount_source(arg_root_what
, "root="))
1179 const char *bind
= startswith(arg_root_what
, "bind:");
1181 if (!path_is_valid(bind
) || !path_is_absolute(bind
)) {
1182 log_debug("Invalid root=bind: source path, ignoring: %s", bind
);
1186 what
= strdup(bind
);
1190 extra_opts
= "bind";
1192 } else if (streq(arg_root_what
, "tmpfs")) {
1193 /* If root=tmpfs is specified, then take this as shortcut for a writable tmpfs mount as root */
1195 what
= strdup("rootfs"); /* just a pretty name, to show up in /proc/self/mountinfo */
1199 fstype
= arg_root_fstype
?: "tmpfs"; /* tmpfs, unless overridden */
1200 if (streq(fstype
, "tmpfs") && !fstab_test_option(arg_root_options
, "mode\0"))
1201 extra_opts
= "mode=0755"; /* root directory should not be world/group writable, unless overridden */
1204 what
= fstab_node_to_udev_node(arg_root_what
);
1208 fstype
= arg_root_fstype
; /* if not specified explicitly, don't default to anything here */
1209 default_rw
= false; /* read-only, unless overridden */
1212 _cleanup_free_
char *combined_options
= NULL
;
1213 if (strdup_to(&combined_options
, arg_root_options
) < 0)
1216 if (arg_root_rw
>= 0 || !fstab_test_option(combined_options
, "ro\0" "rw\0"))
1217 if (!strextend_with_separator(&combined_options
, ",", arg_root_rw
> 0 || (arg_root_rw
< 0 && default_rw
) ? "rw" : "ro"))
1221 if (!strextend_with_separator(&combined_options
, ",", extra_opts
))
1224 log_debug("Found entry what=%s where=/sysroot type=%s opts=%s", what
, strna(fstype
), strempty(combined_options
));
1226 /* Only honor x-systemd.makefs and .validatefs here, others are not relevant in initrd/not used
1227 * at all (also see mandatory_mount_drop_unapplicable_options()) */
1228 flags
= fstab_options_to_flags(combined_options
, /* is_swap = */ false) & (MOUNT_MAKEFS
|MOUNT_VALIDATEFS
);
1230 return add_mount("/proc/cmdline",
1234 /* original_where= */ NULL
,
1237 /* passno= */ is_device_path(what
) ? 1 : 0,
1239 SPECIAL_INITRD_ROOT_FS_TARGET
,
1243 static int add_sysroot_usr_mount(void) {
1244 _cleanup_free_
char *what
= NULL
;
1245 const char *extra_opts
= NULL
;
1246 bool makefs
, validatefs
;
1249 /* Returns 0 if we didn't do anything, > 0 if we either generated a unit for the /usr/ mount, or we
1250 * know for sure something else did */
1252 if (!arg_usr_what
&& !arg_usr_fstype
&& !arg_usr_options
)
1255 if (arg_root_what
&& !arg_usr_what
) {
1256 /* Copy over the root device, in case the /usr mount just differs in a mount option (consider btrfs subvolumes) */
1257 arg_usr_what
= strdup(arg_root_what
);
1262 if (arg_root_fstype
&& !arg_usr_fstype
) {
1263 arg_usr_fstype
= strdup(arg_root_fstype
);
1264 if (!arg_usr_fstype
)
1268 if (arg_root_options
&& !arg_usr_options
) {
1269 arg_usr_options
= strdup(arg_root_options
);
1270 if (!arg_usr_options
)
1274 if (!validate_root_or_usr_mount_source(arg_usr_what
, "mount.usr="))
1277 const char *bind
= startswith(arg_usr_what
, "bind:");
1279 if (!path_is_valid(bind
) || !path_is_absolute(bind
)) {
1280 log_debug("Invalid mount.usr=bind: source path, ignoring: %s", bind
);
1284 what
= strdup(bind
);
1288 extra_opts
= "bind";
1290 what
= fstab_node_to_udev_node(arg_usr_what
);
1295 _cleanup_free_
char *combined_options
= NULL
;
1296 if (strdup_to(&combined_options
, arg_usr_options
) < 0)
1299 if (!fstab_test_option(combined_options
, "ro\0" "rw\0"))
1300 if (!strextend_with_separator(&combined_options
, ",", arg_root_rw
> 0 ? "rw" : "ro"))
1304 if (!strextend_with_separator(&combined_options
, ",", extra_opts
))
1307 /* When mounting /usr from the initrd, we add an extra level of indirection: we first mount the /usr/
1308 * partition to /sysusr/usr/, and then afterwards bind mount that to /sysroot/usr/. We do this so
1309 * that we can cover for systems that initially only have a /usr/ around and where the root fs needs
1310 * to be synthesized, based on configuration included in /usr/, e.g. systemd-repart. Software like
1311 * this should order itself after initrd-usr-fs.target and before initrd-fs.target; and it should
1312 * look into both /sysusr/ and /sysroot/ for the configuration data to apply. */
1314 log_debug("Found entry what=%s where=/sysusr/usr type=%s opts=%s", what
, strna(arg_usr_fstype
), strempty(combined_options
));
1316 /* Only honor x-systemd.makefs and .validatefs here, others are not relevant in initrd/not used
1317 * at all (also see mandatory_mount_drop_unapplicable_options()) */
1318 makefs
= fstab_test_option(combined_options
, "x-systemd.makefs\0");
1319 validatefs
= fstab_test_option(combined_options
, "x-systemd.validatefs\0");
1321 r
= add_mount("/proc/cmdline",
1325 /* original_where= */ NULL
,
1328 /* passno= */ is_device_path(what
) ? 1 : 0,
1329 makefs
? MOUNT_MAKEFS
: 0,
1330 SPECIAL_INITRD_USR_FS_TARGET
,
1335 r
= add_sysusr_sysroot_usr_bind_mount("/proc/cmdline", validatefs
);
1342 static int add_sysroot_usr_mount_or_fallback(void) {
1345 r
= add_sysroot_usr_mount();
1349 /* OK, so we didn't write anything out for /sysusr/usr/ nor /sysroot/usr/. In this case, let's make
1350 * sure that initrd-usr-fs.target is at least ordered after sysroot.mount so that services that order
1351 * themselves after it get the guarantee that /usr/ is definitely mounted somewhere. */
1353 return generator_add_symlink(
1355 SPECIAL_INITRD_USR_FS_TARGET
,
1360 static int add_volatile_root(void) {
1362 /* Let's add in systemd-remount-volatile.service which will remount the root device to tmpfs if this is
1363 * requested (or as an overlayfs), leaving only /usr from the root mount inside. */
1365 if (!IN_SET(arg_volatile_mode
, VOLATILE_YES
, VOLATILE_OVERLAY
))
1368 return generator_add_symlink(arg_dest
, SPECIAL_INITRD_ROOT_FS_TARGET
, "requires",
1369 SYSTEM_DATA_UNIT_DIR
"/" SPECIAL_VOLATILE_ROOT_SERVICE
);
1372 static int add_volatile_var(void) {
1374 if (arg_volatile_mode
!= VOLATILE_STATE
)
1377 /* If requested, mount /var as tmpfs, but do so only if there's nothing else defined for this. */
1379 return add_mount("/proc/cmdline",
1383 /* original_where= */ NULL
,
1385 "mode=0755" TMPFS_LIMITS_VAR
,
1388 SPECIAL_LOCAL_FS_TARGET
,
1389 /* extra_after= */ NULL
);
1392 static int add_mounts_from_cmdline(void) {
1395 /* Handle each entries found in cmdline as a fstab entry. */
1397 FOREACH_ARRAY(m
, arg_mounts
, arg_n_mounts
) {
1398 if (m
->for_initrd
&& !in_initrd())
1401 RET_GATHER(r
, parse_fstab_one("/proc/cmdline",
1407 /* prefix_sysroot = */ !m
->for_initrd
&& in_initrd(),
1408 /* accept_root = */ true,
1409 /* use_swap_enabled = */ false));
1415 static int add_mounts_from_creds(bool prefix_sysroot
) {
1416 _cleanup_free_
void *b
= NULL
;
1421 assert(in_initrd() || !prefix_sysroot
);
1423 r
= read_credential_with_decryption(
1424 in_initrd() && !prefix_sysroot
? "fstab.extra.initrd" : "fstab.extra",
1429 _cleanup_fclose_
FILE *f
= NULL
;
1430 f
= fmemopen_unlocked(b
, bs
, "r");
1436 while ((me
= getmntent(f
)))
1437 RET_GATHER(r
, parse_fstab_one("/run/credentials",
1443 /* prefix_sysroot = */ prefix_sysroot
,
1444 /* accept_root = */ true,
1445 /* use_swap_enabled = */ true));
1450 static int parse_proc_cmdline_item(const char *key
, const char *value
, void *data
) {
1455 /* root=, usr=, usrfstype= and roofstype= may occur more than once, the last
1456 * instance should take precedence. In the case of multiple rootflags=
1457 * or usrflags= the arguments should be concatenated */
1459 if (STR_IN_SET(key
, "fstab", "rd.fstab")) {
1461 r
= value
? parse_boolean(value
) : 1;
1463 log_warning("Failed to parse fstab switch %s. Ignoring.", value
);
1465 arg_fstab_enabled
= fstab_set_enabled(r
);
1467 } else if (streq(key
, "root")) {
1469 if (proc_cmdline_value_missing(key
, value
))
1472 return free_and_strdup_warn(&arg_root_what
, empty_to_null(value
));
1474 } else if (streq(key
, "rootfstype")) {
1476 if (proc_cmdline_value_missing(key
, value
))
1479 return free_and_strdup_warn(&arg_root_fstype
, empty_to_null(value
));
1481 } else if (streq(key
, "rootflags")) {
1483 if (proc_cmdline_value_missing(key
, value
))
1486 if (!strextend_with_separator(&arg_root_options
, ",", value
))
1489 } else if (streq(key
, "roothash")) {
1491 if (proc_cmdline_value_missing(key
, value
))
1494 return free_and_strdup_warn(&arg_root_hash
, empty_to_null(value
));
1496 } else if (streq(key
, "mount.usr")) {
1498 if (proc_cmdline_value_missing(key
, value
))
1501 return free_and_strdup_warn(&arg_usr_what
, empty_to_null(value
));
1503 } else if (streq(key
, "mount.usrfstype")) {
1505 if (proc_cmdline_value_missing(key
, value
))
1508 return free_and_strdup_warn(&arg_usr_fstype
, empty_to_null(value
));
1510 } else if (streq(key
, "mount.usrflags")) {
1512 if (proc_cmdline_value_missing(key
, value
))
1515 if (!strextend_with_separator(&arg_usr_options
, ",", value
))
1518 } else if (streq(key
, "usrhash")) {
1520 if (proc_cmdline_value_missing(key
, value
))
1523 return free_and_strdup_warn(&arg_usr_hash
, empty_to_null(value
));
1525 } else if (streq(key
, "rw") && !value
)
1527 else if (streq(key
, "ro") && !value
)
1528 arg_root_rw
= false;
1529 else if (streq(key
, "systemd.volatile")) {
1533 m
= volatile_mode_from_string(value
);
1535 log_warning_errno(m
, "Failed to parse systemd.volatile= argument: %s", value
);
1537 arg_volatile_mode
= m
;
1539 arg_volatile_mode
= VOLATILE_YES
;
1541 } else if (streq(key
, "systemd.swap")) {
1543 r
= value
? parse_boolean(value
) : 1;
1545 log_warning("Failed to parse systemd.swap switch %s. Ignoring.", value
);
1547 arg_swap_enabled
= r
;
1549 } else if (streq(key
, "systemd.verity")) {
1551 r
= value
? parse_boolean(value
) : 1;
1553 log_warning("Failed to parse systemd.verity= kernel command line switch %s. Ignoring.", value
);
1557 } else if (STR_IN_SET(key
, "systemd.mount-extra", "rd.systemd.mount-extra")) {
1559 if (proc_cmdline_value_missing(key
, value
))
1562 r
= mount_array_add(startswith(key
, "rd."), value
);
1564 log_warning("Failed to parse systemd.mount-extra= option, ignoring: %s", value
);
1566 } else if (STR_IN_SET(key
, "systemd.swap-extra", "rd.systemd.swap-extra")) {
1568 if (proc_cmdline_value_missing(key
, value
))
1571 r
= mount_array_add_swap(startswith(key
, "rd."), value
);
1573 log_warning("Failed to parse systemd.swap-extra= option, ignoring: %s", value
);
1579 static int determine_device(
1589 /* If we have a hash but no device then Verity is used, and we use the DM device. */
1599 *what
= path_join("/dev/mapper/", name
);
1603 /* Verity is always read-only */
1606 if (options
&& !strextend_with_separator(options
, ",", "ro"))
1609 log_info("Using verity %s device %s.", name
, *what
);
1613 static int determine_root(void) {
1614 return determine_device(&arg_root_what
, &arg_root_rw
, NULL
, arg_root_hash
, "root");
1617 static int determine_usr(void) {
1618 return determine_device(&arg_usr_what
, NULL
, &arg_usr_options
, arg_usr_hash
, "usr");
1621 /* If arg_sysroot_check is false, run as generator in the usual fashion.
1622 * If it is true, check /sysroot/etc/fstab for any units that we'd want to mount
1623 * in the initrd, and call daemon-reload. We will get reinvoked as a generator,
1624 * with /sysroot/etc/fstab available, and then we can write additional units based
1626 static int run_generator(void) {
1629 r
= proc_cmdline_parse(parse_proc_cmdline_item
, NULL
, 0);
1631 log_warning_errno(r
, "Failed to parse kernel command line, ignoring: %m");
1633 (void) determine_root();
1634 (void) determine_usr();
1636 if (arg_sysroot_check
) {
1637 r
= parse_fstab(/* prefix_sysroot = */ true);
1639 log_debug("Nothing interesting found, not doing daemon-reload.");
1641 r
= do_daemon_reload();
1647 /* Always honour root= and usr= in the kernel command line if we are in an initrd */
1649 RET_GATHER(r
, add_sysroot_mount());
1651 RET_GATHER(r
, add_sysroot_usr_mount_or_fallback());
1653 RET_GATHER(r
, add_volatile_root());
1655 RET_GATHER(r
, add_volatile_var());
1657 /* Honour /etc/fstab only when that's enabled */
1658 if (arg_fstab_enabled
) {
1659 /* Parse the local /etc/fstab, possibly from the initrd */
1660 RET_GATHER(r
, parse_fstab(/* prefix_sysroot = */ false));
1662 /* If running in the initrd also parse the /etc/fstab from the host */
1664 RET_GATHER(r
, parse_fstab(/* prefix_sysroot = */ true));
1666 RET_GATHER(r
, generator_enable_remount_fs_service(arg_dest
));
1669 RET_GATHER(r
, add_mounts_from_cmdline());
1671 RET_GATHER(r
, add_mounts_from_creds(/* prefix_sysroot = */ false));
1674 RET_GATHER(r
, add_mounts_from_creds(/* prefix_sysroot = */ true));
1679 static int run(int argc
, char **argv
) {
1680 arg_sysroot_check
= invoked_as(argv
, "systemd-sysroot-fstab-check");
1682 if (arg_sysroot_check
) {
1683 /* Run as in systemd-sysroot-fstab-check mode */
1686 if (strv_length(argv
) > 1)
1687 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1688 "This program takes no arguments.");
1690 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1691 "This program is only useful in the initrd.");
1693 /* Run in generator mode */
1694 log_setup_generator();
1696 if (!IN_SET(strv_length(argv
), 2, 4))
1697 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1698 "This program takes one or three arguments.");
1700 arg_dest
= ASSERT_PTR(argv
[1]);
1701 arg_dest_late
= ASSERT_PTR(argv
[argc
> 3 ? 3 : 1]);
1704 return run_generator();
1707 DEFINE_MAIN_FUNCTION(run
);