1 /* SPDX-License-Identifier: LGPL-2.1+ */
9 #include "alloc-util.h"
10 #include "blkid-util.h"
11 #include "blockdev-util.h"
12 #include "btrfs-util.h"
13 #include "device-util.h"
14 #include "dirent-util.h"
15 #include "dissect-image.h"
17 #include "efi-loader.h"
21 #include "fstab-util.h"
22 #include "generator.h"
25 #include "mountpoint-util.h"
26 #include "parse-util.h"
27 #include "path-util.h"
28 #include "proc-cmdline.h"
30 #include "specifier.h"
31 #include "stat-util.h"
32 #include "string-util.h"
34 #include "unit-name.h"
38 static const char *arg_dest
= NULL
;
39 static bool arg_enabled
= true;
40 static bool arg_root_enabled
= true;
41 static int arg_root_rw
= -1;
43 static int open_parent_block_device(dev_t devnum
, int *ret_fd
) {
44 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
45 const char *name
, *devtype
, *node
;
52 r
= sd_device_new_from_devnum(&d
, 'b', devnum
);
54 return log_debug_errno(r
, "Failed to open device: %m");
56 if (sd_device_get_devname(d
, &name
) < 0) {
57 r
= sd_device_get_syspath(d
, &name
);
59 log_device_debug_errno(d
, r
, "Device %u:%u does not have a name, ignoring: %m",
60 major(devnum
), minor(devnum
));
65 r
= sd_device_get_parent(d
, &parent
);
67 log_device_debug_errno(d
, r
, "Not a partitioned device, ignoring: %m");
71 /* Does it have a devtype? */
72 r
= sd_device_get_devtype(parent
, &devtype
);
74 log_device_debug_errno(parent
, r
, "Parent doesn't have a device type, ignoring: %m");
78 /* Is this a disk or a partition? We only care for disks... */
79 if (!streq(devtype
, "disk")) {
80 log_device_debug(parent
, "Parent isn't a raw disk, ignoring.");
84 /* Does it have a device node? */
85 r
= sd_device_get_devname(parent
, &node
);
87 log_device_debug_errno(parent
, r
, "Parent device does not have device node, ignoring: %m");
91 log_device_debug(d
, "Root device %s.", node
);
93 r
= sd_device_get_devnum(parent
, &pn
);
95 log_device_debug_errno(parent
, r
, "Parent device is not a proper block device, ignoring: %m");
99 fd
= open(node
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
101 return log_error_errno(errno
, "Failed to open %s: %m", node
);
107 static int add_cryptsetup(const char *id
, const char *what
, bool rw
, bool require
, char **device
) {
108 _cleanup_free_
char *e
= NULL
, *n
= NULL
, *d
= NULL
;
109 _cleanup_fclose_
FILE *f
= NULL
;
115 r
= unit_name_from_path(what
, ".device", &d
);
117 return log_error_errno(r
, "Failed to generate unit name: %m");
119 e
= unit_name_escape(id
);
123 r
= unit_name_build("systemd-cryptsetup", e
, ".service", &n
);
125 return log_error_errno(r
, "Failed to generate unit name: %m");
127 r
= generator_open_unit_file(arg_dest
, NULL
, n
, &f
);
131 r
= generator_write_cryptsetup_unit_section(f
, NULL
);
136 "Before=umount.target cryptsetup.target\n"
137 "Conflicts=umount.target\n"
142 r
= generator_write_cryptsetup_service_section(f
, id
, what
, NULL
, rw
? NULL
: "read-only");
146 r
= fflush_and_check(f
);
148 return log_error_errno(r
, "Failed to write file %s: %m", n
);
150 r
= generator_add_symlink(arg_dest
, d
, "wants", n
);
155 dmname
= strjoina("dev-mapper-", e
, ".device");
158 r
= generator_add_symlink(arg_dest
, "cryptsetup.target", "requires", n
);
162 r
= generator_add_symlink(arg_dest
, dmname
, "requires", n
);
167 r
= write_drop_in_format(arg_dest
, dmname
, 50, "job-timeout",
168 "# Automatically generated by systemd-gpt-auto-generator\n\n"
170 "JobTimeoutSec=0"); /* the binary handles timeouts anyway */
172 log_warning_errno(r
, "Failed to write device timeout drop-in, ignoring: %m");
177 ret
= path_join("/dev/mapper", id
);
187 static int add_mount(
194 const char *description
,
197 _cleanup_free_
char *unit
= NULL
, *crypto_what
= NULL
, *p
= NULL
;
198 _cleanup_fclose_
FILE *f
= NULL
;
201 /* Note that we don't apply specifier escaping on the input strings here, since we know they are not configured
202 * externally, but all originate from our own sources here, and hence we know they contain no % characters that
203 * could potentially be understood as specifiers. */
210 log_debug("Adding %s: %s fstype=%s", where
, what
, fstype
?: "(any)");
212 if (streq_ptr(fstype
, "crypto_LUKS")) {
213 r
= add_cryptsetup(id
, what
, rw
, true, &crypto_what
);
221 r
= unit_name_from_path(where
, ".mount", &unit
);
223 return log_error_errno(r
, "Failed to generate unit name: %m");
225 p
= path_join(empty_to_root(arg_dest
), unit
);
231 return log_error_errno(errno
, "Failed to create unit file %s: %m", unit
);
234 "# Automatically generated by systemd-gpt-auto-generator\n\n"
237 "Documentation=man:systemd-gpt-auto-generator(8)\n",
241 fprintf(f
, "Before=%s\n", post
);
243 r
= generator_write_fsck_deps(f
, arg_dest
, what
, where
, fstype
);
247 r
= generator_write_blockdev_dependency(f
, what
);
259 fprintf(f
, "Type=%s\n", fstype
);
262 fprintf(f
, "Options=%s,%s\n", options
, rw
? "rw" : "ro");
264 fprintf(f
, "Options=%s\n", rw
? "rw" : "ro");
266 r
= fflush_and_check(f
);
268 return log_error_errno(r
, "Failed to write unit file %s: %m", p
);
271 return generator_add_symlink(arg_dest
, post
, "requires", unit
);
275 static int path_is_busy(const char *where
) {
278 /* already a mountpoint; generators run during reload */
279 r
= path_is_mount_point(where
, NULL
, AT_SYMLINK_FOLLOW
);
283 /* the directory might not exist on a stateless system */
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
);
293 return log_warning_errno(r
, "Cannot check if \"%s\" is empty: %m", where
);
297 log_debug("\"%s\" already populated, ignoring.", where
);
301 static int add_partition_mount(
302 DissectedPartition
*p
,
305 const char *description
) {
310 r
= path_is_busy(where
);
312 return r
< 0 ? r
: 0;
322 SPECIAL_LOCAL_FS_TARGET
);
325 static int add_swap(const char *path
) {
326 _cleanup_free_
char *name
= NULL
, *unit
= NULL
;
327 _cleanup_fclose_
FILE *f
= NULL
;
332 /* Disable the swap auto logic if at least one swap is defined in /etc/fstab, see #6192. */
333 r
= fstab_has_fstype("swap");
335 return log_error_errno(r
, "Failed to parse fstab: %m");
337 log_debug("swap specified in fstab, ignoring.");
341 log_debug("Adding swap: %s", path
);
343 r
= unit_name_from_path(path
, ".swap", &name
);
345 return log_error_errno(r
, "Failed to generate unit name: %m");
347 unit
= path_join(empty_to_root(arg_dest
), name
);
351 f
= fopen(unit
, "wxe");
353 return log_error_errno(errno
, "Failed to create unit file %s: %m", unit
);
356 "# Automatically generated by systemd-gpt-auto-generator\n\n"
358 "Description=Swap Partition\n"
359 "Documentation=man:systemd-gpt-auto-generator(8)\n");
361 r
= generator_write_blockdev_dependency(f
, path
);
371 r
= fflush_and_check(f
);
373 return log_error_errno(r
, "Failed to write unit file %s: %m", unit
);
375 return generator_add_symlink(arg_dest
, SPECIAL_SWAP_TARGET
, "wants", name
);
378 static int add_automount(
385 const char *description
,
388 _cleanup_free_
char *unit
= NULL
;
389 _cleanup_fclose_
FILE *f
= NULL
;
390 const char *opt
= "noauto", *p
;
398 opt
= strjoina(options
, ",", opt
);
411 r
= unit_name_from_path(where
, ".automount", &unit
);
413 return log_error_errno(r
, "Failed to generate unit name: %m");
415 p
= prefix_roota(arg_dest
, unit
);
418 return log_error_errno(errno
, "Failed to create unit file %s: %m", unit
);
421 "# Automatically generated by systemd-gpt-auto-generator\n\n"
424 "Documentation=man:systemd-gpt-auto-generator(8)\n"
427 "TimeoutIdleSec="USEC_FMT
"\n",
430 timeout
/ USEC_PER_SEC
);
432 r
= fflush_and_check(f
);
434 return log_error_errno(r
, "Failed to write unit file %s: %m", p
);
436 return generator_add_symlink(arg_dest
, SPECIAL_LOCAL_FS_TARGET
, "wants", unit
);
439 static const char *esp_or_xbootldr_options(const DissectedPartition
*p
) {
442 /* if we probed vfat or have no idea about the file system then assume these file systems are vfat
443 * and thus understand "umask=0077". If we detected something else then don't specify any options and
444 * use kernel defaults. */
446 if (!p
->fstype
|| streq(p
->fstype
, "vfat"))
452 static int add_xbootldr(DissectedPartition
*p
) {
458 log_debug("In initrd, ignoring the XBOOTLDR partition.");
462 r
= fstab_is_mount_point("/boot");
464 return log_error_errno(r
, "Failed to parse fstab: %m");
466 log_debug("/boot specified in fstab, ignoring XBOOTLDR partition.");
470 r
= path_is_busy("/boot");
476 return add_automount("boot",
481 esp_or_xbootldr_options(p
),
482 "Boot Loader Partition",
487 static int add_esp(DissectedPartition
*p
, bool has_xbootldr
) {
488 const char *esp_path
= NULL
, *id
= NULL
;
494 log_debug("In initrd, ignoring the ESP.");
498 /* If /efi exists we'll use that. Otherwise we'll use /boot, as that's usually the better choice, but
499 * only if there's no explicit XBOOTLDR partition around. */
500 if (access("/efi", F_OK
) < 0) {
502 return log_error_errno(errno
, "Failed to determine whether /efi exists: %m");
504 /* Use /boot as fallback, but only if there's no XBOOTLDR partition */
515 /* We create an .automount which is not overridden by the .mount from the fstab generator. */
516 r
= fstab_is_mount_point(esp_path
);
518 return log_error_errno(r
, "Failed to parse fstab: %m");
520 log_debug("%s specified in fstab, ignoring.", esp_path
);
524 r
= path_is_busy(esp_path
);
531 sd_id128_t loader_uuid
;
533 /* If this is an EFI boot, be extra careful, and only mount the ESP if it was the ESP used for booting. */
535 r
= efi_loader_get_device_part_uuid(&loader_uuid
);
537 log_debug("EFI loader partition unknown.");
541 return log_error_errno(r
, "Failed to read ESP partition UUID: %m");
543 if (!sd_id128_equal(p
->uuid
, loader_uuid
)) {
544 log_debug("Partition for %s does not appear to be the partition we are booted from.", p
->node
);
548 log_debug("Not an EFI boot, skipping ESP check.");
550 return add_automount(id
,
555 esp_or_xbootldr_options(p
),
556 "EFI System Partition Automount",
560 static int add_esp(DissectedPartition
*p
, bool has_xbootldr
) {
565 static int add_root_rw(DissectedPartition
*p
) {
572 log_debug("In initrd, not generating drop-in for systemd-remount-fs.service.");
576 if (arg_root_rw
>= 0) {
577 log_debug("Parameter ro/rw specified on kernel command line, not generating drop-in for systemd-remount-fs.service.");
582 log_debug("Root partition marked read-only in GPT partition table, not generating drop-in for systemd-remount-fs.service.");
586 (void) generator_enable_remount_fs_service(arg_dest
);
588 path
= strjoina(arg_dest
, "/systemd-remount-fs.service.d/50-remount-rw.conf");
590 r
= write_string_file(path
,
591 "# Automatically generated by systemd-gpt-generator\n\n"
593 "Environment=SYSTEMD_REMOUNT_ROOT_RW=1\n",
594 WRITE_STRING_FILE_CREATE
|WRITE_STRING_FILE_NOFOLLOW
|WRITE_STRING_FILE_MKDIR_0755
);
596 return log_error_errno(r
, "Failed to write drop-in file %s: %m", path
);
602 static int add_root_cryptsetup(void) {
604 /* If a device /dev/gpt-auto-root-luks appears, then make it pull in systemd-cryptsetup-root.service, which
605 * sets it up, and causes /dev/gpt-auto-root to appear which is all we are looking for. */
607 return add_cryptsetup("root", "/dev/gpt-auto-root-luks", true, false, NULL
);
611 static int add_root_mount(void) {
615 if (!is_efi_boot()) {
616 log_debug("Not a EFI boot, not creating root mount.");
620 r
= efi_loader_get_device_part_uuid(NULL
);
622 log_notice("EFI loader partition unknown, exiting.\n"
623 "(The boot loader did not set EFI variable LoaderDevicePartUUID.)");
626 return log_error_errno(r
, "Failed to read ESP partition UUID: %m");
628 /* OK, we have an ESP partition, this is fantastic, so let's
629 * wait for a root device to show up. A udev rule will create
630 * the link for us under the right name. */
633 r
= generator_write_initrd_root_device_deps(arg_dest
, "/dev/gpt-auto-root");
637 r
= add_root_cryptsetup();
642 /* Note that we do not need to enable systemd-remount-fs.service here. If
643 * /etc/fstab exists, systemd-fstab-generator will pull it in for us. */
647 "/dev/gpt-auto-root",
648 in_initrd() ? "/sysroot" : "/",
653 in_initrd() ? SPECIAL_INITRD_ROOT_FS_TARGET
: SPECIAL_LOCAL_FS_TARGET
);
659 static int enumerate_partitions(dev_t devnum
) {
660 _cleanup_close_
int fd
= -1;
661 _cleanup_(dissected_image_unrefp
) DissectedImage
*m
= NULL
;
664 r
= open_parent_block_device(devnum
, &fd
);
668 r
= dissect_image(fd
, NULL
, 0, DISSECT_IMAGE_GPT_ONLY
|DISSECT_IMAGE_NO_UDEV
, &m
);
670 log_debug_errno(r
, "No suitable partition table found, ignoring.");
674 return log_error_errno(r
, "Failed to dissect: %m");
676 if (m
->partitions
[PARTITION_SWAP
].found
) {
677 k
= add_swap(m
->partitions
[PARTITION_SWAP
].node
);
682 if (m
->partitions
[PARTITION_XBOOTLDR
].found
) {
683 k
= add_xbootldr(m
->partitions
+ PARTITION_XBOOTLDR
);
688 if (m
->partitions
[PARTITION_ESP
].found
) {
689 k
= add_esp(m
->partitions
+ PARTITION_ESP
, m
->partitions
[PARTITION_XBOOTLDR
].found
);
694 if (m
->partitions
[PARTITION_HOME
].found
) {
695 k
= add_partition_mount(m
->partitions
+ PARTITION_HOME
, "home", "/home", "Home Partition");
700 if (m
->partitions
[PARTITION_SRV
].found
) {
701 k
= add_partition_mount(m
->partitions
+ PARTITION_SRV
, "srv", "/srv", "Server Data Partition");
706 if (m
->partitions
[PARTITION_VAR
].found
) {
707 k
= add_partition_mount(m
->partitions
+ PARTITION_VAR
, "var", "/var", "Variable Data Partition");
712 if (m
->partitions
[PARTITION_TMP
].found
) {
713 k
= add_partition_mount(m
->partitions
+ PARTITION_TMP
, "var-tmp", "/var/tmp", "Temporary Data Partition");
718 if (m
->partitions
[PARTITION_ROOT
].found
) {
719 k
= add_root_rw(m
->partitions
+ PARTITION_ROOT
);
727 static int add_mounts(void) {
731 r
= get_block_device_harder("/", &devno
);
733 return log_error_errno(r
, "Failed to determine block device of root file system: %m");
735 r
= get_block_device_harder("/usr", &devno
);
737 return log_error_errno(r
, "Failed to determine block device of /usr file system: %m");
739 _cleanup_free_
char *p
= NULL
;
742 /* If the root mount has been replaced by some form of volatile file system (overlayfs), the
743 * original root block device node is symlinked in /run/systemd/volatile-root. Let's read that
745 r
= readlink_malloc("/run/systemd/volatile-root", &p
);
747 log_debug("Neither root nor /usr file system are on a (single) block device.");
751 return log_error_errno(r
, "Failed to read symlink /run/systemd/volatile-root: %m");
753 r
= device_path_parse_major_minor(p
, &m
, &devno
);
755 return log_error_errno(r
, "Failed to parse major/minor device node: %m");
757 return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK
), "Volatile root device is of wrong type.");
761 return enumerate_partitions(devno
);
764 static int parse_proc_cmdline_item(const char *key
, const char *value
, void *data
) {
769 if (proc_cmdline_key_streq(key
, "systemd.gpt_auto") ||
770 proc_cmdline_key_streq(key
, "rd.systemd.gpt_auto")) {
772 r
= value
? parse_boolean(value
) : 1;
774 log_warning_errno(r
, "Failed to parse gpt-auto switch \"%s\", ignoring: %m", value
);
778 } else if (proc_cmdline_key_streq(key
, "root")) {
780 if (proc_cmdline_value_missing(key
, value
))
783 /* Disable root disk logic if there's a root= value
784 * specified (unless it happens to be "gpt-auto") */
786 if (!streq(value
, "gpt-auto")) {
787 arg_root_enabled
= false;
788 log_debug("Disabling root partition auto-detection, root= is defined.");
791 } else if (proc_cmdline_key_streq(key
, "roothash")) {
793 if (proc_cmdline_value_missing(key
, value
))
796 /* Disable root disk logic if there's roothash= defined (i.e. verity enabled) */
798 arg_root_enabled
= false;
800 } else if (proc_cmdline_key_streq(key
, "rw") && !value
)
802 else if (proc_cmdline_key_streq(key
, "ro") && !value
)
808 static int run(const char *dest
, const char *dest_early
, const char *dest_late
) {
811 assert_se(arg_dest
= dest_late
);
813 if (detect_container() > 0) {
814 log_debug("In a container, exiting.");
818 r
= proc_cmdline_parse(parse_proc_cmdline_item
, NULL
, 0);
820 log_warning_errno(r
, "Failed to parse kernel command line, ignoring: %m");
823 log_debug("Disabled, exiting.");
827 if (arg_root_enabled
)
828 r
= add_root_mount();
839 DEFINE_MAIN_GENERATOR_FUNCTION(run
);