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
, 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_stub_measured(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=0"); /* 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
, *p
= 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 p
= path_join(empty_to_root(arg_dest
), unit
);
221 return log_error_errno(errno
, "Failed to create unit file %s: %m", unit
);
224 "# Automatically generated by systemd-gpt-auto-generator\n\n"
227 "Documentation=man:systemd-gpt-auto-generator(8)\n",
231 fprintf(f
, "Before=%s\n", post
);
233 r
= generator_write_fsck_deps(f
, arg_dest
, what
, where
, fstype
);
237 r
= generator_write_blockdev_dependency(f
, what
);
249 fprintf(f
, "Type=%s\n", fstype
);
252 fprintf(f
, "Options=%s\n", options
);
254 r
= fflush_and_check(f
);
256 return log_error_errno(r
, "Failed to write unit file %s: %m", p
);
259 r
= generator_hook_up_growfs(arg_dest
, where
, post
);
265 r
= generator_hook_up_pcrfs(arg_dest
, where
, post
);
271 r
= generator_add_symlink(arg_dest
, post
, "requires", unit
);
279 static int path_is_busy(const char *where
) {
284 /* already a mountpoint; generators run during reload */
285 r
= path_is_mount_point(where
, NULL
, AT_SYMLINK_FOLLOW
);
288 /* The directory will be created by the mount or automount unit when it is started. */
293 return log_warning_errno(r
, "Cannot check if \"%s\" is a mount point: %m", where
);
295 /* not a mountpoint but it contains files */
296 r
= dir_is_empty(where
, /* ignore_hidden_or_backup= */ false);
298 log_debug("\"%s\" is not a directory, ignoring.", where
);
301 return log_warning_errno(r
, "Cannot check if \"%s\" is empty: %m", where
);
303 log_debug("\"%s\" already populated, ignoring.", where
);
310 static int add_partition_mount(
311 PartitionDesignator d
,
312 DissectedPartition
*p
,
315 const char *description
) {
317 _cleanup_free_
char *options
= NULL
;
322 r
= path_is_busy(where
);
324 return r
< 0 ? r
: 0;
326 r
= partition_pick_mount_options(
328 dissected_partition_fstype(p
),
332 /* ret_ms_flags= */ NULL
);
343 /* measure= */ STR_IN_SET(id
, "root", "var"), /* by default measure rootfs and /var, since they contain the "identity" of the system */
346 SPECIAL_LOCAL_FS_TARGET
);
349 static int add_partition_swap(DissectedPartition
*p
) {
351 _cleanup_free_
char *name
= NULL
, *unit
= NULL
, *crypto_what
= NULL
;
352 _cleanup_fclose_
FILE *f
= NULL
;
358 if (!arg_swap_enabled
)
361 /* Disable the swap auto logic if at least one swap is defined in /etc/fstab, see #6192. */
362 r
= fstab_has_fstype("swap");
364 return log_error_errno(r
, "Failed to parse fstab: %m");
366 log_debug("swap specified in fstab, ignoring.");
370 if (streq_ptr(p
->fstype
, "crypto_LUKS")) {
371 r
= add_cryptsetup("swap", p
->node
, /* rw= */ true, /* require= */ true, /* measure= */ false, &crypto_what
);
378 log_debug("Adding swap: %s", what
);
380 r
= unit_name_from_path(what
, ".swap", &name
);
382 return log_error_errno(r
, "Failed to generate unit name: %m");
384 unit
= path_join(empty_to_root(arg_dest
), name
);
388 f
= fopen(unit
, "wxe");
390 return log_error_errno(errno
, "Failed to create unit file %s: %m", unit
);
393 "# Automatically generated by systemd-gpt-auto-generator\n\n"
395 "Description=Swap Partition\n"
396 "Documentation=man:systemd-gpt-auto-generator(8)\n");
398 r
= generator_write_blockdev_dependency(f
, what
);
408 r
= fflush_and_check(f
);
410 return log_error_errno(r
, "Failed to write unit file %s: %m", unit
);
412 return generator_add_symlink(arg_dest
, SPECIAL_SWAP_TARGET
, "wants", name
);
415 static int add_automount(
423 const char *description
,
426 _cleanup_free_
char *unit
= NULL
, *p
= NULL
;
427 _cleanup_fclose_
FILE *f
= NULL
;
440 /* measure= */ false,
447 r
= unit_name_from_path(where
, ".automount", &unit
);
449 return log_error_errno(r
, "Failed to generate unit name: %m");
451 p
= path_join(arg_dest
, unit
);
457 return log_error_errno(errno
, "Failed to create unit file %s: %m", unit
);
460 "# Automatically generated by systemd-gpt-auto-generator\n\n"
463 "Documentation=man:systemd-gpt-auto-generator(8)\n"
466 "TimeoutIdleSec="USEC_FMT
"\n",
469 timeout
/ USEC_PER_SEC
);
471 r
= fflush_and_check(f
);
473 return log_error_errno(r
, "Failed to write unit file %s: %m", p
);
475 return generator_add_symlink(arg_dest
, SPECIAL_LOCAL_FS_TARGET
, "wants", unit
);
478 static int slash_boot_in_fstab(void) {
479 static int cache
= -1;
484 cache
= fstab_is_mount_point("/boot");
486 return log_error_errno(cache
, "Failed to parse fstab: %m");
490 static int slash_efi_in_fstab(void) {
491 static int cache
= -1;
496 cache
= fstab_is_mount_point("/efi");
498 return log_error_errno(cache
, "Failed to parse fstab: %m");
502 static bool slash_boot_exists(void) {
503 static int cache
= -1;
508 if (access("/boot", F_OK
) >= 0)
509 return (cache
= true);
511 log_error_errno(errno
, "Failed to determine whether /boot/ exists, assuming no: %m");
513 log_debug_errno(errno
, "/boot/: %m");
514 return (cache
= false);
517 static int add_partition_xbootldr(DissectedPartition
*p
) {
518 _cleanup_free_
char *options
= NULL
;
524 log_debug("In initrd, ignoring the XBOOTLDR partition.");
528 r
= slash_boot_in_fstab();
532 log_debug("/boot/ specified in fstab, ignoring XBOOTLDR partition.");
536 r
= path_is_busy("/boot");
542 r
= partition_pick_mount_options(
544 dissected_partition_fstype(p
),
546 /* discard= */ false,
548 /* ret_ms_flags= */ NULL
);
550 return log_error_errno(r
, "Failed to determine default mount options for /boot/: %m");
552 return add_automount(
560 "Boot Loader Partition",
565 static int add_partition_esp(DissectedPartition
*p
, bool has_xbootldr
) {
566 const char *esp_path
= NULL
, *id
= NULL
;
567 _cleanup_free_
char *options
= NULL
;
573 log_debug("In initrd, ignoring the ESP.");
577 /* If /boot/ is present, unused, and empty, we'll take that.
578 * Otherwise, if /efi/ is unused and empty (or missing), we'll take that.
579 * Otherwise, we do nothing.
581 if (!has_xbootldr
&& slash_boot_exists()) {
582 r
= slash_boot_in_fstab();
586 r
= path_is_busy("/boot");
597 r
= slash_efi_in_fstab();
603 r
= path_is_busy("/efi");
614 sd_id128_t loader_uuid
;
616 /* If this is an EFI boot, be extra careful, and only mount the ESP if it was the ESP used for booting. */
618 r
= efi_loader_get_device_part_uuid(&loader_uuid
);
620 log_debug("EFI loader partition unknown.");
624 return log_error_errno(r
, "Failed to read ESP partition UUID: %m");
626 if (!sd_id128_equal(p
->uuid
, loader_uuid
)) {
627 log_debug("Partition for %s does not appear to be the partition we are booted from.", p
->node
);
631 log_debug("Not an EFI boot, skipping ESP check.");
633 r
= partition_pick_mount_options(
635 dissected_partition_fstype(p
),
637 /* discard= */ false,
639 /* ret_ms_flags= */ NULL
);
641 return log_error_errno(r
, "Failed to determine default mount options for %s: %m", esp_path
);
643 return add_automount(
651 "EFI System Partition Automount",
655 static int add_partition_esp(DissectedPartition
*p
, bool has_xbootldr
) {
660 static int add_partition_root_rw(DissectedPartition
*p
) {
667 log_debug("In initrd, not generating drop-in for systemd-remount-fs.service.");
671 if (arg_root_rw
>= 0) {
672 log_debug("Parameter ro/rw specified on kernel command line, not generating drop-in for systemd-remount-fs.service.");
677 log_debug("Root partition marked read-only in GPT partition table, not generating drop-in for systemd-remount-fs.service.");
681 (void) generator_enable_remount_fs_service(arg_dest
);
683 path
= strjoina(arg_dest
, "/systemd-remount-fs.service.d/50-remount-rw.conf");
685 r
= write_string_file(path
,
686 "# Automatically generated by systemd-gpt-auto-generator\n\n"
688 "Environment=SYSTEMD_REMOUNT_ROOT_RW=1\n",
689 WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_NOFOLLOW
|WRITE_STRING_FILE_MKDIR_0755
);
691 return log_error_errno(r
, "Failed to write drop-in file %s: %m", path
);
697 static int add_root_cryptsetup(void) {
698 #if HAVE_LIBCRYPTSETUP
700 /* If a device /dev/gpt-auto-root-luks appears, then make it pull in systemd-cryptsetup-root.service, which
701 * sets it up, and causes /dev/gpt-auto-root to appear which is all we are looking for. */
703 return add_cryptsetup("root", "/dev/gpt-auto-root-luks", /* rw= */ true, /* require= */ false, /* measure= */ true, NULL
);
710 static int add_root_mount(void) {
712 _cleanup_free_
char *options
= NULL
;
715 if (!is_efi_boot()) {
716 log_debug("Not an EFI boot, not creating root mount.");
720 r
= efi_loader_get_device_part_uuid(NULL
);
722 log_notice("EFI loader partition unknown, exiting.\n"
723 "(The boot loader did not set EFI variable LoaderDevicePartUUID.)");
726 return log_error_errno(r
, "Failed to read ESP partition UUID: %m");
728 /* OK, we have an ESP partition, this is fantastic, so let's wait for a root device to show up. A
729 * udev rule will create the link for us under the right name. */
732 r
= generator_write_initrd_root_device_deps(arg_dest
, "/dev/gpt-auto-root");
736 r
= add_root_cryptsetup();
741 /* Note that we do not need to enable systemd-remount-fs.service here. If
742 * /etc/fstab exists, systemd-fstab-generator will pull it in for us. */
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 enumerate_partitions(dev_t devnum
) {
775 _cleanup_(dissected_image_unrefp
) DissectedImage
*m
= NULL
;
776 _cleanup_(loop_device_unrefp
) LoopDevice
*loop
= NULL
;
777 _cleanup_free_
char *devname
= NULL
;
780 r
= block_get_whole_disk(devnum
, &devnum
);
782 return log_debug_errno(r
, "Failed to get whole block device for " DEVNUM_FORMAT_STR
": %m",
783 DEVNUM_FORMAT_VAL(devnum
));
785 r
= devname_from_devnum(S_IFBLK
, devnum
, &devname
);
787 return log_debug_errno(r
, "Failed to get device node of " DEVNUM_FORMAT_STR
": %m",
788 DEVNUM_FORMAT_VAL(devnum
));
790 /* Let's take a LOCK_SH lock on the block device, in case udevd is already running. If we don't take
791 * the lock, udevd might end up issuing BLKRRPART in the middle, and we don't want that, since that
792 * might remove all partitions while we are operating on them. */
793 r
= loop_device_open_from_path(devname
, O_RDONLY
, LOCK_SH
, &loop
);
795 return log_debug_errno(r
, "Failed to open %s: %m", devname
);
797 r
= dissect_loop_device(
800 /* mount_options= */ NULL
,
801 arg_image_policy
?: &image_policy_host
,
802 DISSECT_IMAGE_GPT_ONLY
|
803 DISSECT_IMAGE_USR_NO_ROOT
|
804 DISSECT_IMAGE_DISKSEQ_DEVNODE
|
805 DISSECT_IMAGE_ALLOW_EMPTY
,
806 /* NB! Unlike most other places where we dissect block devices we do not use
807 * DISSECT_IMAGE_ADD_PARTITION_DEVICES here: we want that the kernel finds the
808 * devices, and udev probes them before we mount them via .mount units much later
809 * on. And thus we also don't set DISSECT_IMAGE_PIN_PARTITION_DEVICES here, because
810 * we don't actually mount anything immediately. */
813 bool ok
= r
== -ENOPKG
;
814 dissect_log_error(ok
? LOG_DEBUG
: LOG_ERR
, r
, devname
, NULL
);
818 if (m
->partitions
[PARTITION_SWAP
].found
) {
819 k
= add_partition_swap(m
->partitions
+ PARTITION_SWAP
);
824 if (m
->partitions
[PARTITION_XBOOTLDR
].found
) {
825 k
= add_partition_xbootldr(m
->partitions
+ PARTITION_XBOOTLDR
);
830 if (m
->partitions
[PARTITION_ESP
].found
) {
831 k
= add_partition_esp(m
->partitions
+ PARTITION_ESP
, m
->partitions
[PARTITION_XBOOTLDR
].found
);
836 if (m
->partitions
[PARTITION_HOME
].found
) {
837 k
= add_partition_mount(PARTITION_HOME
, m
->partitions
+ PARTITION_HOME
, "home", "/home", "Home Partition");
842 if (m
->partitions
[PARTITION_SRV
].found
) {
843 k
= add_partition_mount(PARTITION_SRV
, m
->partitions
+ PARTITION_SRV
, "srv", "/srv", "Server Data Partition");
848 if (m
->partitions
[PARTITION_VAR
].found
) {
849 k
= add_partition_mount(PARTITION_VAR
, m
->partitions
+ PARTITION_VAR
, "var", "/var", "Variable Data Partition");
854 if (m
->partitions
[PARTITION_TMP
].found
) {
855 k
= add_partition_mount(PARTITION_TMP
, m
->partitions
+ PARTITION_TMP
, "var-tmp", "/var/tmp", "Temporary Data Partition");
860 if (m
->partitions
[PARTITION_ROOT
].found
) {
861 k
= add_partition_root_rw(m
->partitions
+ PARTITION_ROOT
);
869 static int add_mounts(void) {
873 r
= blockdev_get_root(LOG_ERR
, &devno
);
877 log_debug("Skipping automatic GPT dissection logic, root file system not backed by a (single) whole block device.");
881 return enumerate_partitions(devno
);
884 static int parse_proc_cmdline_item(const char *key
, const char *value
, void *data
) {
889 if (proc_cmdline_key_streq(key
, "systemd.gpt_auto") ||
890 proc_cmdline_key_streq(key
, "rd.systemd.gpt_auto")) {
892 r
= value
? parse_boolean(value
) : 1;
894 log_warning_errno(r
, "Failed to parse gpt-auto switch \"%s\", ignoring: %m", value
);
898 } else if (proc_cmdline_key_streq(key
, "root")) {
900 if (proc_cmdline_value_missing(key
, value
))
903 /* Disable root disk logic if there's a root= value
904 * specified (unless it happens to be "gpt-auto") */
906 if (!streq(value
, "gpt-auto")) {
907 arg_root_enabled
= false;
908 log_debug("Disabling root partition auto-detection, root= is defined.");
911 } else if (proc_cmdline_key_streq(key
, "roothash")) {
913 if (proc_cmdline_value_missing(key
, value
))
916 /* Disable root disk logic if there's roothash= defined (i.e. verity enabled) */
918 arg_root_enabled
= false;
920 } else if (streq(key
, "rootfstype")) {
922 if (proc_cmdline_value_missing(key
, value
))
925 return free_and_strdup_warn(&arg_root_fstype
, value
);
927 } else if (streq(key
, "rootflags")) {
929 if (proc_cmdline_value_missing(key
, value
))
932 if (!strextend_with_separator(&arg_root_options
, ",", value
))
935 } else if (proc_cmdline_key_streq(key
, "rw") && !value
)
937 else if (proc_cmdline_key_streq(key
, "ro") && !value
)
939 else if (proc_cmdline_key_streq(key
, "systemd.image_policy"))
940 return parse_image_policy_argument(optarg
, &arg_image_policy
);
942 else if (proc_cmdline_key_streq(key
, "systemd.swap")) {
944 r
= value
? parse_boolean(value
) : 1;
946 log_warning_errno(r
, "Failed to parse swap switch \"%s\", ignoring: %m", value
);
948 arg_swap_enabled
= r
;
950 if (!arg_swap_enabled
)
951 log_debug("Disabling swap partitions auto-detection, systemd.swap=no is defined.");
958 static int run(const char *dest
, const char *dest_early
, const char *dest_late
) {
961 assert_se(arg_dest
= dest_late
);
963 if (detect_container() > 0) {
964 log_debug("In a container, exiting.");
968 r
= proc_cmdline_parse(parse_proc_cmdline_item
, NULL
, 0);
970 log_warning_errno(r
, "Failed to parse kernel command line, ignoring: %m");
973 log_debug("Disabled, exiting.");
977 if (arg_root_enabled
)
978 r
= add_root_mount();
989 DEFINE_MAIN_GENERATOR_FUNCTION(run
);