diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c index aa56215825..363f07c24a 100644 --- a/src/udev/udev-builtin-blkid.c +++ b/src/udev/udev-builtin-blkid.c @@ -22,12 +22,14 @@ #include "alloc-util.h" #include "blkid-util.h" +#include "blockdev-util.h" #include "device-util.h" #include "devnum-util.h" #include "efi-loader.h" #include "errno-util.h" #include "fd-util.h" #include "gpt.h" +#include "initrd-util.h" #include "parse-util.h" #include "string-util.h" #include "strv.h" @@ -129,101 +131,163 @@ static int find_gpt_root(UdevEvent *event, blkid_probe pr, const char *loop_back #if defined(SD_GPT_ROOT_NATIVE) && ENABLE_EFI sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev); - _cleanup_free_ char *root_label = NULL; - bool found_esp_or_xbootldr = false, need_esp_or_xbootldr; - sd_id128_t root_id = SD_ID128_NULL, esp_or_xbootldr = SD_ID128_NULL; int r; assert(event); assert(pr); - /* Iterate through the partitions on this disk, and see if the UEFI ESP or XBOOTLDR partition we - * booted from is on it. If so, find the newest root partition, and add a property indicating its - * partition UUID. We also do this if we are dealing with a loopback block device whose "backing - * filename" field is set to the string "root". In the latter case we do not search for ESP or - * XBOOTLDR. */ + /* In the initrd: Iterate through the partitions on this disk, and see if the UEFI ESP or XBOOTLDR + * partition we booted from is on it. If so, find the newest root partition, and add a property + * indicating its partition UUID. We also do this if we are dealing with a loopback block device + * whose "backing filename" field is set to the string "root". In the latter case we do not search + * for ESP or XBOOTLDR. + * + * After the initrd→host transition: look at the current block device mounted at / and set the same + * properties to its whole block device. */ if (!device_is_devtype(dev, "disk")) { log_device_debug(dev, "Skipping GPT root logic on partition block device."); return 0; } - r = efi_loader_get_device_part_uuid(&esp_or_xbootldr); - if (r < 0) { - if (r != -ENOENT && !ERRNO_IS_NEG_NOT_SUPPORTED(r)) - return log_debug_errno(r, "Unable to determine loader partition UUID: %m"); + sd_id128_t esp_or_xbootldr = SD_ID128_NULL; + bool need_esp_or_xbootldr; + dev_t root_devno = 0; + if (in_initrd()) { + /* In the initrd look at the boot loader provided data (and loopback backing fname) to find + * our *future* root */ - log_device_debug(dev, "No loader partition UUID EFI variable set, not using partition data to search for default root block device."); + r = efi_loader_get_device_part_uuid(&esp_or_xbootldr); + if (r < 0) { + if (r != -ENOENT && !ERRNO_IS_NEG_NOT_SUPPORTED(r)) + return log_debug_errno(r, "Unable to determine loader partition UUID: %m"); - /* NB: if an ESP/xbootldr field is set, we always use that. We do this in order to guarantee - * systematic behaviour. */ - if (!STRPTR_IN_SET(loop_backing_fname, "rootdisk", "rootdisk.raw")) { - log_device_debug(dev, "Device is not a loopback block device with reference string 'root', not considering block device as default root block device."); + log_device_debug(dev, "No loader partition UUID EFI variable set, not using partition data to search for default root block device."); + + /* NB: if an ESP/xbootldr field is set, we always use that. We do this in order to guarantee + * systematic behaviour. */ + if (!STRPTR_IN_SET(loop_backing_fname, "rootdisk", "rootdisk.raw")) { + log_device_debug(dev, "Device is not a loopback block device with reference string 'root', not considering block device as default root block device."); + return 0; + } + + /* OK, we have now sufficiently identified this device as the right root "whole" device, + * hence no need to bother with searching for ESP/XBOOTLDR */ + need_esp_or_xbootldr = false; + } else + /* We now know the the ESP/xbootldr UUID, but we cannot be sure yet it's on this block + * device, hence look for it among partitions now */ + need_esp_or_xbootldr = true; + } else { + /* On the main system look at the *current* root instead */ + + r = blockdev_get_root(LOG_DEBUG, &root_devno); + if (r < 0) { + log_device_debug_errno(dev, r, "Unable to determine current root block device, skipping gpt-auto probing: %m"); + return 0; + } + if (r == 0) { + log_device_debug(dev, "Root block device not backed by a (single) whole block device, skipping gpt-auto probing."); return 0; } - /* OK, we have now sufficiently identified this device as the right root "whole" device, - * hence no need to bother with searching for ESP/XBOOTLDR */ + dev_t whole_devno; + r = block_get_whole_disk(root_devno, &whole_devno); + if (r < 0) + return log_device_debug_errno(dev, r, "Failed to find whole block device for root block device: %m"); + + dev_t this_devno; + r = sd_device_get_devnum(dev, &this_devno); + if (r < 0) + return log_device_debug_errno(dev, r, "Failed to get device major/minor of device: %m"); + + if (whole_devno != this_devno) { + log_device_debug(dev, "This device is not the current root block device."); + return 0; + } + + /* We don't need to check ESP/XBOOTLDR UUID, we *know* what our root disk is */ need_esp_or_xbootldr = false; - } else - /* We now know the the ESP/xbootldr UUID, but we cannot be sure yet it's on this block - * device, hence look for it among partitions now */ - need_esp_or_xbootldr = true; + } errno = 0; blkid_partlist pl = blkid_probe_get_partitions(pr); if (!pl) return log_device_debug_errno(dev, errno_or_else(ENOMEM), "Failed to probe partitions: %m"); - int nvals = blkid_partlist_numof_partitions(pl); - for (int i = 0; i < nvals; i++) { - blkid_partition pp; - const char *label; - sd_id128_t type, id; + sd_id128_t root_id = SD_ID128_NULL; + bool found_esp_or_xbootldr = false; - pp = blkid_partlist_get_partition(pl, i); - if (!pp) - continue; + if (root_devno != 0) { + /* If we already know the root partition, let's verify its type ID and then directly query + * its ID */ - r = blkid_partition_get_uuid_id128(pp, &id); - if (r < 0) { - log_device_debug_errno(dev, r, "Failed to get partition UUID, ignoring: %m"); - continue; + blkid_partition root_partition = blkid_partlist_devno_to_partition(pl, root_devno); + if (root_partition) { + sd_id128_t type; + r = blkid_partition_get_type_id128(root_partition, &type); + if (r < 0) + log_device_debug_errno(dev, r, "Failed to get root partition type UUID, ignoring: %m"); + else if (sd_id128_equal(type, SD_GPT_ROOT_NATIVE)) { + r = blkid_partition_get_uuid_id128(root_partition, &root_id); + if (r < 0) + log_device_debug_errno(dev, r, "Failed to get partition UUID, ignoring: %m"); + } } + } else { + /* We do not know the root partition, let's search for it. */ - r = blkid_partition_get_type_id128(pp, &type); - if (r < 0) { - log_device_debug_errno(dev, r, "Failed to get partition type UUID, ignoring: %m"); - continue; - } + _cleanup_free_ char *root_label = NULL; + int nvals = blkid_partlist_numof_partitions(pl); + for (int i = 0; i < nvals; i++) { + blkid_partition pp; + const char *label; + sd_id128_t type, id; - label = blkid_partition_get_name(pp); /* returns NULL if empty */ - - if (need_esp_or_xbootldr && sd_id128_in_set(type, SD_GPT_ESP, SD_GPT_XBOOTLDR)) { - - /* We found an ESP or XBOOTLDR, let's see if it matches the ESP/XBOOTLDR we booted from. */ - if (sd_id128_equal(id, esp_or_xbootldr)) - found_esp_or_xbootldr = true; - - } else if (sd_id128_equal(type, SD_GPT_ROOT_NATIVE)) { - unsigned long long flags; - - flags = blkid_partition_get_flags(pp); - if (flags & SD_GPT_FLAG_NO_AUTO) + pp = blkid_partlist_get_partition(pl, i); + if (!pp) continue; - /* systemd-sysupdate expects empty partitions to be marked with an "_empty" label, hence ignore them here. */ - if (streq_ptr(label, "_empty")) + r = blkid_partition_get_uuid_id128(pp, &id); + if (r < 0) { + log_device_debug_errno(dev, r, "Failed to get partition UUID, ignoring: %m"); continue; + } - /* We found a suitable root partition, let's remember the first one, or the one with - * the newest version, as determined by comparing the partition labels. */ + r = blkid_partition_get_type_id128(pp, &type); + if (r < 0) { + log_device_debug_errno(dev, r, "Failed to get partition type UUID, ignoring: %m"); + continue; + } - if (sd_id128_is_null(root_id) || strverscmp_improved(label, root_label) > 0) { - root_id = id; + label = blkid_partition_get_name(pp); /* returns NULL if empty */ - if (free_and_strdup(&root_label, label) < 0) - return log_oom_debug(); + if (need_esp_or_xbootldr && sd_id128_in_set(type, SD_GPT_ESP, SD_GPT_XBOOTLDR)) { + + /* We found an ESP or XBOOTLDR, let's see if it matches the ESP/XBOOTLDR we booted from. */ + if (sd_id128_equal(id, esp_or_xbootldr)) + found_esp_or_xbootldr = true; + + } else if (sd_id128_equal(type, SD_GPT_ROOT_NATIVE)) { + unsigned long long flags; + + flags = blkid_partition_get_flags(pp); + if (flags & SD_GPT_FLAG_NO_AUTO) + continue; + + /* systemd-sysupdate expects empty partitions to be marked with an "_empty" label, hence ignore them here. */ + if (streq_ptr(label, "_empty")) + continue; + + /* We found a suitable root partition, let's remember the first one, or the one with + * the newest version, as determined by comparing the partition labels. */ + + if (sd_id128_is_null(root_id) || strverscmp_improved(label, root_label) > 0) { + root_id = id; + + if (free_and_strdup(&root_label, label) < 0) + return log_oom_debug(); + } } } }