1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
10 #include "alloc-util.h"
11 #include "blkid-util.h"
12 #include "blockdev-util.h"
13 #include "btrfs-util.h"
14 #include "device-util.h"
15 #include "devnum-util.h"
16 #include "dirent-util.h"
17 #include "dissect-image.h"
19 #include "efi-loader.h"
23 #include "fstab-util.h"
24 #include "generator.h"
26 #include "image-policy.h"
27 #include "initrd-util.h"
28 #include "mountpoint-util.h"
29 #include "parse-util.h"
30 #include "path-util.h"
31 #include "proc-cmdline.h"
33 #include "specifier.h"
34 #include "stat-util.h"
35 #include "string-util.h"
37 #include "unit-name.h"
40 static const char *arg_dest
= NULL
;
41 static bool arg_enabled
= true;
42 static bool arg_root_enabled
= true;
43 static bool arg_swap_enabled
= true;
44 static char *arg_root_fstype
= NULL
;
45 static char *arg_root_options
= NULL
;
46 static int arg_root_rw
= -1;
47 static ImagePolicy
*arg_image_policy
= NULL
;
49 STATIC_DESTRUCTOR_REGISTER(arg_image_policy
, image_policy_freep
);
51 STATIC_DESTRUCTOR_REGISTER(arg_root_fstype
, freep
);
52 STATIC_DESTRUCTOR_REGISTER(arg_root_options
, freep
);
54 static int add_cryptsetup(
62 #if HAVE_LIBCRYPTSETUP
63 _cleanup_free_
char *e
= NULL
, *n
= NULL
, *d
= NULL
, *options
= NULL
;
64 _cleanup_fclose_
FILE *f
= NULL
;
70 r
= unit_name_from_path(what
, ".device", &d
);
72 return log_error_errno(r
, "Failed to generate unit name: %m");
74 e
= unit_name_escape(id
);
78 r
= unit_name_build("systemd-cryptsetup", e
, ".service", &n
);
80 return log_error_errno(r
, "Failed to generate unit name: %m");
82 r
= generator_open_unit_file(arg_dest
, /* source = */ NULL
, n
, &f
);
86 r
= generator_write_cryptsetup_unit_section(f
, NULL
);
91 "Before=umount.target cryptsetup.target\n"
92 "Conflicts=umount.target\n"
98 options
= strdup("read-only");
104 /* We only measure the root volume key into PCR 15 if we are booted with sd-stub (i.e. in a
105 * UKI), and sd-stub measured the UKI. We do this in order not to step into people's own PCR
106 * assignment, under the assumption that people who are fine to use sd-stub with its PCR
107 * assignments are also OK with our PCR 15 use here. */
109 r
= efi_measured_uki(LOG_WARNING
);
111 log_debug("Will not measure volume key of volume '%s', not booted via systemd-stub with measurements enabled.", id
);
113 if (!strextend_with_separator(&options
, ",", "tpm2-measure-pcr=yes"))
118 r
= generator_write_cryptsetup_service_section(f
, id
, what
, NULL
, options
);
122 r
= fflush_and_check(f
);
124 return log_error_errno(r
, "Failed to write file %s: %m", n
);
126 r
= generator_add_symlink(arg_dest
, d
, "wants", n
);
130 const char *dmname
= strjoina("dev-mapper-", e
, ".device");
133 r
= generator_add_symlink(arg_dest
, "cryptsetup.target", "requires", n
);
137 r
= generator_add_symlink(arg_dest
, dmname
, "requires", n
);
142 r
= write_drop_in_format(arg_dest
, dmname
, 50, "job-timeout",
143 "# Automatically generated by systemd-gpt-auto-generator\n\n"
145 "JobTimeoutSec=infinity"); /* the binary handles timeouts anyway */
147 log_warning_errno(r
, "Failed to write device timeout drop-in, ignoring: %m");
152 s
= path_join("/dev/mapper", id
);
161 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
162 "Partition is encrypted, but systemd-gpt-auto-generator was compiled without libcryptsetup support");
166 static int add_mount(
175 const char *description
,
178 _cleanup_free_
char *unit
= NULL
, *crypto_what
= NULL
;
179 _cleanup_fclose_
FILE *f
= NULL
;
182 /* Note that we don't apply specifier escaping on the input strings here, since we know they are not configured
183 * externally, but all originate from our own sources here, and hence we know they contain no % characters that
184 * could potentially be understood as specifiers. */
191 log_debug("Adding %s: %s fstype=%s", where
, what
, fstype
?: "(any)");
193 if (streq_ptr(fstype
, "crypto_LUKS")) {
194 r
= add_cryptsetup(id
, what
, rw
, /* require= */ true, measure
, &crypto_what
);
201 r
= dissect_fstype_ok(fstype
);
203 return log_error_errno(r
, "Unable to determine of dissected file system type '%s' is permitted: %m", fstype
);
205 return log_error_errno(
206 SYNTHETIC_ERRNO(EIDRM
),
207 "Refusing to automatically mount uncommon file system '%s' to '%s'.",
211 r
= unit_name_from_path(where
, ".mount", &unit
);
213 return log_error_errno(r
, "Failed to generate unit name: %m");
215 r
= generator_open_unit_file(arg_dest
, /* source = */ NULL
, unit
, &f
);
222 "Documentation=man:systemd-gpt-auto-generator(8)\n",
226 fprintf(f
, "Before=%s\n", post
);
228 r
= generator_write_fsck_deps(f
, arg_dest
, what
, where
, fstype
);
232 r
= generator_write_blockdev_dependency(f
, what
);
244 fprintf(f
, "Type=%s\n", fstype
);
247 fprintf(f
, "Options=%s\n", options
);
249 r
= fflush_and_check(f
);
251 return log_error_errno(r
, "Failed to write unit %s: %m", unit
);
254 r
= generator_hook_up_growfs(arg_dest
, where
, post
);
260 r
= generator_hook_up_pcrfs(arg_dest
, where
, post
);
266 r
= generator_add_symlink(arg_dest
, post
, "requires", unit
);
274 static int path_is_busy(const char *where
) {
279 /* already a mountpoint; generators run during reload */
280 r
= path_is_mount_point(where
, NULL
, AT_SYMLINK_FOLLOW
);
283 /* The directory will be created by the mount or automount unit when it is started. */
288 return log_warning_errno(r
, "Cannot check if \"%s\" is a mount point: %m", where
);
290 /* not a mountpoint but it contains files */
291 r
= dir_is_empty(where
, /* ignore_hidden_or_backup= */ false);
293 log_debug("\"%s\" is not a directory, ignoring.", where
);
296 return log_warning_errno(r
, "Cannot check if \"%s\" is empty: %m", where
);
298 log_debug("\"%s\" already populated, ignoring.", where
);
305 static int add_partition_mount(
306 PartitionDesignator d
,
307 DissectedPartition
*p
,
310 const char *description
) {
312 _cleanup_free_
char *options
= NULL
;
317 r
= path_is_busy(where
);
319 return r
< 0 ? r
: 0;
321 r
= partition_pick_mount_options(
323 dissected_partition_fstype(p
),
327 /* ret_ms_flags= */ NULL
);
338 /* measure= */ STR_IN_SET(id
, "root", "var"), /* by default measure rootfs and /var, since they contain the "identity" of the system */
341 SPECIAL_LOCAL_FS_TARGET
);
344 static int add_partition_swap(DissectedPartition
*p
) {
346 _cleanup_free_
char *name
= NULL
, *crypto_what
= NULL
;
347 _cleanup_fclose_
FILE *f
= NULL
;
353 if (!arg_swap_enabled
)
356 /* Disable the swap auto logic if at least one swap is defined in /etc/fstab, see #6192. */
357 r
= fstab_has_fstype("swap");
359 return log_error_errno(r
, "Failed to parse fstab: %m");
361 log_debug("swap specified in fstab, ignoring.");
365 if (streq_ptr(p
->fstype
, "crypto_LUKS")) {
366 r
= add_cryptsetup("swap", p
->node
, /* rw= */ true, /* require= */ true, /* measure= */ false, &crypto_what
);
373 log_debug("Adding swap: %s", what
);
375 r
= unit_name_from_path(what
, ".swap", &name
);
377 return log_error_errno(r
, "Failed to generate unit name: %m");
379 r
= generator_open_unit_file(arg_dest
, /* source = */ NULL
, name
, &f
);
385 "Description=Swap Partition\n"
386 "Documentation=man:systemd-gpt-auto-generator(8)\n");
388 r
= generator_write_blockdev_dependency(f
, what
);
398 r
= fflush_and_check(f
);
400 return log_error_errno(r
, "Failed to write unit %s: %m", name
);
402 return generator_add_symlink(arg_dest
, SPECIAL_SWAP_TARGET
, "wants", name
);
405 static int add_automount(
413 const char *description
,
416 _cleanup_free_
char *unit
= NULL
;
417 _cleanup_fclose_
FILE *f
= NULL
;
430 /* measure= */ false,
437 r
= unit_name_from_path(where
, ".automount", &unit
);
439 return log_error_errno(r
, "Failed to generate unit name: %m");
441 r
= generator_open_unit_file(arg_dest
, /* source = */ NULL
, unit
, &f
);
448 "Documentation=man:systemd-gpt-auto-generator(8)\n"
451 "TimeoutIdleSec="USEC_FMT
"\n",
454 timeout
/ USEC_PER_SEC
);
456 r
= fflush_and_check(f
);
458 return log_error_errno(r
, "Failed to write unit %s: %m", unit
);
460 return generator_add_symlink(arg_dest
, SPECIAL_LOCAL_FS_TARGET
, "wants", unit
);
463 static int slash_boot_in_fstab(void) {
464 static int cache
= -1;
469 cache
= fstab_is_mount_point("/boot");
471 return log_error_errno(cache
, "Failed to parse fstab: %m");
475 static int add_partition_xbootldr(DissectedPartition
*p
) {
476 _cleanup_free_
char *options
= NULL
;
482 log_debug("In initrd, ignoring the XBOOTLDR partition.");
486 r
= slash_boot_in_fstab();
490 log_debug("/boot/ specified in fstab, ignoring XBOOTLDR partition.");
494 r
= path_is_busy("/boot");
500 r
= partition_pick_mount_options(
502 dissected_partition_fstype(p
),
504 /* discard= */ false,
506 /* ret_ms_flags= */ NULL
);
508 return log_error_errno(r
, "Failed to determine default mount options for /boot/: %m");
510 return add_automount(
518 "Boot Loader Partition",
523 static int slash_efi_in_fstab(void) {
524 static int cache
= -1;
529 cache
= fstab_is_mount_point("/efi");
531 return log_error_errno(cache
, "Failed to parse fstab: %m");
535 static bool slash_boot_exists(void) {
536 static int cache
= -1;
541 if (access("/boot", F_OK
) >= 0)
542 return (cache
= true);
544 log_error_errno(errno
, "Failed to determine whether /boot/ exists, assuming no: %m");
546 log_debug_errno(errno
, "/boot/: %m");
547 return (cache
= false);
550 static int add_partition_esp(DissectedPartition
*p
, bool has_xbootldr
) {
551 const char *esp_path
= NULL
, *id
= NULL
;
552 _cleanup_free_
char *options
= NULL
;
558 log_debug("In initrd, ignoring the ESP.");
562 /* Check if there's an existing fstab entry for ESP. If so, we just skip the gpt-auto logic. */
563 r
= fstab_has_node(p
->node
);
565 return log_error_errno(r
,
566 "Failed to check if fstab entry for device '%s' exists: %m", p
->node
);
570 /* If /boot/ is present, unused, and empty, we'll take that.
571 * Otherwise, if /efi/ is unused and empty (or missing), we'll take that.
572 * Otherwise, we do nothing. */
573 if (!has_xbootldr
&& slash_boot_exists()) {
574 r
= slash_boot_in_fstab();
578 r
= path_is_busy("/boot");
589 r
= slash_efi_in_fstab();
595 r
= path_is_busy("/efi");
605 r
= partition_pick_mount_options(
607 dissected_partition_fstype(p
),
609 /* discard= */ false,
611 /* ret_ms_flags= */ NULL
);
613 return log_error_errno(r
, "Failed to determine default mount options for %s: %m", esp_path
);
615 return add_automount(
623 "EFI System Partition Automount",
627 static int add_partition_esp(DissectedPartition
*p
, bool has_xbootldr
) {
632 static int add_partition_root_rw(DissectedPartition
*p
) {
637 assert(!in_initrd());
639 /* Invoked on the main system (not initrd), to honour GPT flag 60 on the root fs (ro) */
641 if (arg_root_rw
>= 0) {
642 log_debug("Parameter ro/rw specified on kernel command line, not generating drop-in for systemd-remount-fs.service.");
647 log_debug("Root partition marked read-only in GPT partition table, not generating drop-in for systemd-remount-fs.service.");
651 r
= generator_enable_remount_fs_service(arg_dest
);
655 path
= strjoina(arg_dest
, "/systemd-remount-fs.service.d/50-remount-rw.conf");
657 r
= write_string_file(path
,
658 "# Automatically generated by systemd-gpt-auto-generator\n\n"
660 "Environment=SYSTEMD_REMOUNT_ROOT_RW=1\n",
661 WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_NOFOLLOW
|WRITE_STRING_FILE_MKDIR_0755
);
663 return log_error_errno(r
, "Failed to write drop-in file %s: %m", path
);
668 static int add_partition_root_growfs(DissectedPartition
*p
) {
671 assert(!in_initrd());
673 /* Invoked on the main system (not initrd), to honour GPT flag 59 on the root fs (growfs) */
676 log_debug("Root partition not marked for growing the file system in the GPT partition table, not generating drop-in for systemd-growfs-root.service.");
680 return generator_hook_up_growfs(arg_dest
, "/", SPECIAL_LOCAL_FS_TARGET
);
683 static int add_partition_root_flags(DissectedPartition
*p
) {
687 assert(!in_initrd());
689 RET_GATHER(r
, add_partition_root_growfs(p
));
690 RET_GATHER(r
, add_partition_root_rw(p
));
696 static int add_root_cryptsetup(void) {
697 #if HAVE_LIBCRYPTSETUP
699 /* If a device /dev/gpt-auto-root-luks appears, then make it pull in systemd-cryptsetup-root.service, which
700 * sets it up, and causes /dev/gpt-auto-root to appear which is all we are looking for. */
702 return add_cryptsetup("root", "/dev/gpt-auto-root-luks", /* rw= */ true, /* require= */ false, /* measure= */ true, NULL
);
709 static int add_root_mount(void) {
711 _cleanup_free_
char *options
= NULL
;
714 if (!is_efi_boot()) {
715 log_debug("Not an EFI boot, not creating root mount.");
719 r
= efi_loader_get_device_part_uuid(NULL
);
721 log_notice("EFI loader partition unknown, exiting.\n"
722 "(The boot loader did not set EFI variable LoaderDevicePartUUID.)");
725 return log_error_errno(r
, "Failed to read loader partition UUID: %m");
727 /* OK, we have an ESP/XBOOTLDR partition, this is fantastic, so let's wait for a root device to show up.
728 * A udev rule will create the link for us under the right name. */
731 r
= generator_write_initrd_root_device_deps(arg_dest
, "/dev/gpt-auto-root");
735 r
= add_root_cryptsetup();
740 /* Note that we do not need to enable systemd-remount-fs.service here. If /etc/fstab exists,
741 * systemd-fstab-generator will pull it in for us, and otherwise add_partition_root_flags() will do
742 * it, after the initrd transition. */
744 r
= partition_pick_mount_options(
750 /* ret_ms_flags= */ NULL
);
752 return log_error_errno(r
, "Failed to pick root mount options: %m");
754 if (arg_root_options
)
755 if (!strextend_with_separator(&options
, ",", arg_root_options
))
760 "/dev/gpt-auto-root",
761 in_initrd() ? "/sysroot" : "/",
763 /* rw= */ arg_root_rw
> 0,
768 in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET
: SPECIAL_LOCAL_FS_TARGET
);
774 static int process_loader_partitions(DissectedPartition
*esp
, DissectedPartition
*xbootldr
) {
775 sd_id128_t loader_uuid
;
781 if (!is_efi_boot()) {
782 log_debug("Not an EFI boot, skipping loader partition UUID check.");
786 /* Let's check if LoaderDevicePartUUID points to either ESP or XBOOTLDR. We prefer it pointing
787 * to the ESP, but we accept XBOOTLDR too. If it points to neither of them, don't mount any
788 * loader partitions, since they are not the ones used for booting. */
790 r
= efi_loader_get_device_part_uuid(&loader_uuid
);
792 log_debug_errno(r
, "EFI loader partition unknown, skipping ESP and XBOOTLDR mounts.");
796 return log_debug_errno(r
, "Failed to read loader partition UUID, ignoring: %m");
798 if (esp
->found
&& sd_id128_equal(esp
->uuid
, loader_uuid
))
801 if (xbootldr
->found
&& sd_id128_equal(xbootldr
->uuid
, loader_uuid
)) {
802 log_debug("LoaderDevicePartUUID points to XBOOTLDR partition.");
806 log_debug("LoaderDevicePartUUID points to neither ESP nor XBOOTLDR, ignoring.");
813 RET_GATHER(r
, add_partition_xbootldr(xbootldr
));
815 RET_GATHER(r
, add_partition_esp(esp
, xbootldr
->found
));
820 static int enumerate_partitions(dev_t devnum
) {
821 _cleanup_(dissected_image_unrefp
) DissectedImage
*m
= NULL
;
822 _cleanup_(loop_device_unrefp
) LoopDevice
*loop
= NULL
;
823 _cleanup_free_
char *devname
= NULL
;
826 assert(!in_initrd());
828 /* Run on the final root fs (not in the initrd), to mount auxiliary partitions, and hook in rw
829 * remount and growfs of the root partition */
831 r
= block_get_whole_disk(devnum
, &devnum
);
833 return log_debug_errno(r
, "Failed to get whole block device for " DEVNUM_FORMAT_STR
": %m",
834 DEVNUM_FORMAT_VAL(devnum
));
836 r
= devname_from_devnum(S_IFBLK
, devnum
, &devname
);
838 return log_debug_errno(r
, "Failed to get device node of " DEVNUM_FORMAT_STR
": %m",
839 DEVNUM_FORMAT_VAL(devnum
));
841 /* Let's take a LOCK_SH lock on the block device, in case udevd is already running. If we don't take
842 * the lock, udevd might end up issuing BLKRRPART in the middle, and we don't want that, since that
843 * might remove all partitions while we are operating on them. */
844 r
= loop_device_open_from_path(devname
, O_RDONLY
, LOCK_SH
, &loop
);
846 return log_debug_errno(r
, "Failed to open %s: %m", devname
);
848 r
= dissect_loop_device(
851 /* mount_options= */ NULL
,
852 arg_image_policy
?: &image_policy_host
,
853 DISSECT_IMAGE_GPT_ONLY
|
854 DISSECT_IMAGE_USR_NO_ROOT
|
855 DISSECT_IMAGE_DISKSEQ_DEVNODE
|
856 DISSECT_IMAGE_ALLOW_EMPTY
,
857 /* NB! Unlike most other places where we dissect block devices we do not use
858 * DISSECT_IMAGE_ADD_PARTITION_DEVICES here: we want that the kernel finds the
859 * devices, and udev probes them before we mount them via .mount units much later
860 * on. And thus we also don't set DISSECT_IMAGE_PIN_PARTITION_DEVICES here, because
861 * we don't actually mount anything immediately. */
864 bool ok
= r
== -ENOPKG
;
865 dissect_log_error(ok
? LOG_DEBUG
: LOG_ERR
, r
, devname
, NULL
);
869 if (m
->partitions
[PARTITION_SWAP
].found
)
870 RET_GATHER(r
, add_partition_swap(m
->partitions
+ PARTITION_SWAP
));
872 RET_GATHER(r
, process_loader_partitions(m
->partitions
+ PARTITION_ESP
, m
->partitions
+ PARTITION_XBOOTLDR
));
874 if (m
->partitions
[PARTITION_HOME
].found
)
875 RET_GATHER(r
, add_partition_mount(PARTITION_HOME
, m
->partitions
+ PARTITION_HOME
,
876 "home", "/home", "Home Partition"));
878 if (m
->partitions
[PARTITION_SRV
].found
)
879 RET_GATHER(r
, add_partition_mount(PARTITION_SRV
, m
->partitions
+ PARTITION_SRV
,
880 "srv", "/srv", "Server Data Partition"));
882 if (m
->partitions
[PARTITION_VAR
].found
)
883 RET_GATHER(r
, add_partition_mount(PARTITION_VAR
, m
->partitions
+ PARTITION_VAR
,
884 "var", "/var", "Variable Data Partition"));
886 if (m
->partitions
[PARTITION_TMP
].found
)
887 RET_GATHER(r
, add_partition_mount(PARTITION_TMP
, m
->partitions
+ PARTITION_TMP
,
888 "var-tmp", "/var/tmp", "Temporary Data Partition"));
890 if (m
->partitions
[PARTITION_ROOT
].found
)
891 RET_GATHER(r
, add_partition_root_flags(m
->partitions
+ PARTITION_ROOT
));
896 static int add_mounts(void) {
900 r
= blockdev_get_root(LOG_ERR
, &devno
);
904 log_debug("Skipping automatic GPT dissection logic, root file system not backed by a (single) whole block device.");
908 return enumerate_partitions(devno
);
911 static int parse_proc_cmdline_item(const char *key
, const char *value
, void *data
) {
916 if (proc_cmdline_key_streq(key
, "systemd.gpt_auto") ||
917 proc_cmdline_key_streq(key
, "rd.systemd.gpt_auto")) {
919 r
= value
? parse_boolean(value
) : 1;
921 log_warning_errno(r
, "Failed to parse gpt-auto switch \"%s\", ignoring: %m", value
);
925 } else if (streq(key
, "root")) {
927 if (proc_cmdline_value_missing(key
, value
))
930 /* Disable root disk logic if there's a root= value
931 * specified (unless it happens to be "gpt-auto") */
933 if (!streq(value
, "gpt-auto")) {
934 arg_root_enabled
= false;
935 log_debug("Disabling root partition auto-detection, root= is defined.");
938 } else if (streq(key
, "roothash")) {
940 if (proc_cmdline_value_missing(key
, value
))
943 /* Disable root disk logic if there's roothash= defined (i.e. verity enabled) */
945 arg_root_enabled
= false;
947 } else if (streq(key
, "rootfstype")) {
949 if (proc_cmdline_value_missing(key
, value
))
952 return free_and_strdup_warn(&arg_root_fstype
, value
);
954 } else if (streq(key
, "rootflags")) {
956 if (proc_cmdline_value_missing(key
, value
))
959 if (!strextend_with_separator(&arg_root_options
, ",", value
))
962 } else if (streq(key
, "rw") && !value
)
964 else if (streq(key
, "ro") && !value
)
966 else if (proc_cmdline_key_streq(key
, "systemd.image_policy"))
967 return parse_image_policy_argument(optarg
, &arg_image_policy
);
969 else if (streq(key
, "systemd.swap")) {
971 r
= value
? parse_boolean(value
) : 1;
973 log_warning_errno(r
, "Failed to parse swap switch \"%s\", ignoring: %m", value
);
975 arg_swap_enabled
= r
;
977 if (!arg_swap_enabled
)
978 log_debug("Disabling swap partitions auto-detection, systemd.swap=no is defined.");
985 static int run(const char *dest
, const char *dest_early
, const char *dest_late
) {
988 assert_se(arg_dest
= dest_late
);
990 if (detect_container() > 0) {
991 log_debug("In a container, exiting.");
995 r
= proc_cmdline_parse(parse_proc_cmdline_item
, NULL
, 0);
997 log_warning_errno(r
, "Failed to parse kernel command line, ignoring: %m");
1000 log_debug("Disabled, exiting.");
1004 if (arg_root_enabled
)
1005 r
= add_root_mount();
1016 DEFINE_MAIN_GENERATOR_FUNCTION(run
);