diff --git a/TODO b/TODO index 4e7d79a860..65d6ee84bd 100644 --- a/TODO +++ b/TODO @@ -167,9 +167,6 @@ Features: * systemd-dissect: maybe add "--attach" and "--detach" verbs which synchronously attach a DDI to a loopback device but not actually mount them. -* gpt-auto-generator: generate device names via /dev/disk/by-diskseq/ to pin - the medium - * pam_systemd_home: add module parameter to control whether to only accept only password or only pcks11/fido2 auth, and then use this to hook nicely into two of the three PAM stacks gdm provides. diff --git a/rules.d/60-persistent-storage.rules b/rules.d/60-persistent-storage.rules index 18588e4c45..86e0165b0b 100644 --- a/rules.d/60-persistent-storage.rules +++ b/rules.d/60-persistent-storage.rules @@ -137,5 +137,6 @@ ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_NAME}=="?*", SYMLINK+="disk/ # the diskseq number from the path, then issue BLKGETDISKSEQ to verify they really got # the right device, to access specific disks in a race-free fashion) ENV{DISKSEQ}=="?*", ENV{DEVTYPE}!="partition", ENV{DISKSEQ}=="?*", ENV{ID_IGNORE_DISKSEQ}!="1", SYMLINK+="disk/by-diskseq/$env{DISKSEQ}" +ENV{DISKSEQ}=="?*", ENV{DEVTYPE}=="partition", ENV{DISKSEQ}=="?*", ENV{ID_IGNORE_DISKSEQ}!="1", SYMLINK+="disk/by-diskseq/$env{DISKSEQ}-part%n" LABEL="persistent_storage_end" diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index 1d626f2a5a..92eef36b4d 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -674,7 +674,8 @@ static int enumerate_partitions(dev_t devnum) { loop, NULL, NULL, DISSECT_IMAGE_GPT_ONLY| - DISSECT_IMAGE_USR_NO_ROOT, + DISSECT_IMAGE_USR_NO_ROOT| + DISSECT_IMAGE_DISKSEQ_DEVNODE, /* NB! Unlike most other places where we dissect block devices we do not use * DISSECT_IMAGE_ADD_PARTITION_DEVICES here: we want that the kernel finds the * devices, and udev probes them before we mount them via .mount units much later diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index 100b8cc8f1..3eefe3efa4 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -322,28 +322,57 @@ static void dissected_partition_done(DissectedPartition *p) { #if HAVE_BLKID static int make_partition_devname( const char *whole_devname, + uint64_t diskseq, int nr, + DissectImageFlags flags, char **ret) { - bool need_p; + _cleanup_free_ char *s = NULL; + int r; assert(whole_devname); - assert(nr > 0); + assert(nr != 0); /* zero is not a valid partition nr */ + assert(ret); - /* Given a whole block device node name (e.g. /dev/sda or /dev/loop7) generate a partition device - * name (e.g. /dev/sda7 or /dev/loop7p5). The rule the kernel uses is simple: if whole block device - * node name ends in a digit, then suffix a 'p', followed by the partition number. Otherwise, just - * suffix the partition number without any 'p'. */ + if (!FLAGS_SET(flags, DISSECT_IMAGE_DISKSEQ_DEVNODE) || diskseq == UINT64_MAX) { - if (isempty(whole_devname)) /* Make sure there *is* a last char */ - return -EINVAL; + /* Given a whole block device node name (e.g. /dev/sda or /dev/loop7) generate a partition + * device name (e.g. /dev/sda7 or /dev/loop7p5). The rule the kernel uses is simple: if whole + * block device node name ends in a digit, then suffix a 'p', followed by the partition + * number. Otherwise, just suffix the partition number without any 'p'. */ - need_p = ascii_isdigit(whole_devname[strlen(whole_devname)-1]); /* Last char a digit? */ + if (nr < 0) { /* whole disk? */ + s = strdup(whole_devname); + if (!s) + return -ENOMEM; + } else { + size_t l = strlen(whole_devname); + if (l < 1) /* underflow check for the subtraction below */ + return -EINVAL; - return asprintf(ret, "%s%s%i", whole_devname, need_p ? "p" : "", nr); + bool need_p = ascii_isdigit(whole_devname[l-1]); /* Last char a digit? */ + + if (asprintf(&s, "%s%s%i", whole_devname, need_p ? "p" : "", nr) < 0) + return -ENOMEM; + } + } else { + if (nr < 0) /* whole disk? */ + r = asprintf(&s, "/dev/disk/by-diskseq/%" PRIu64, diskseq); + else + r = asprintf(&s, "/dev/disk/by-diskseq/%" PRIu64 "-part%i", diskseq, nr); + if (r < 0) + return -ENOMEM; + } + + *ret = TAKE_PTR(s); + return 0; } -static int open_partition(const char *node, bool is_partition, const LoopDevice *loop) { +static int open_partition( + const char *node, + bool is_partition, + const LoopDevice *loop) { + _cleanup_(sd_device_unrefp) sd_device *dev = NULL; _cleanup_close_ int fd = -EBADF; dev_t devnum; @@ -442,6 +471,8 @@ static int dissect_image( * Returns -ENXIO if we couldn't find any partition suitable as root or /usr partition * Returns -ENOTUNIQ if we only found multiple generic partitions and thus don't know what to do with that */ + uint64_t diskseq = m->loop ? m->loop->diskseq : UINT64_MAX; + if (verity && verity->root_hash) { sd_id128_t fsuuid, vuuid; @@ -537,9 +568,9 @@ static int dissect_image( log_debug_errno(r, "Failed to parse file system UUID '%s', ignoring: %m", suuid); } - n = strdup(devname); - if (!n) - return -ENOMEM; + r = make_partition_devname(devname, diskseq, -1, flags, &n); + if (r < 0) + return r; m->single_file_system = true; m->encrypted = streq_ptr(fstype, "crypto_LUKS"); @@ -650,7 +681,9 @@ static int dissect_image( assert((uint64_t) size < UINT64_MAX/512); - r = make_partition_devname(devname, nr, &node); + /* While probing we need the non-diskseq device node name to access the thing, hence mask off + * DISSECT_IMAGE_DISKSEQ_DEVNODE. */ + r = make_partition_devname(devname, diskseq, nr, flags & ~DISSECT_IMAGE_DISKSEQ_DEVNODE, &node); if (r < 0) return r; @@ -862,9 +895,7 @@ static int dissect_image( generic_rw = !(pflags & SD_GPT_FLAG_READ_ONLY); generic_growfs = FLAGS_SET(pflags, SD_GPT_FLAG_GROWFS); generic_uuid = id; - generic_node = strdup(node); - if (!generic_node) - return -ENOMEM; + generic_node = TAKE_PTR(node); } } else if (type.designator == PARTITION_VAR) { @@ -903,7 +934,7 @@ static int dissect_image( } if (type.designator != _PARTITION_DESIGNATOR_INVALID) { - _cleanup_free_ char *t = NULL, *o = NULL, *l = NULL; + _cleanup_free_ char *t = NULL, *o = NULL, *l = NULL, *n = NULL; _cleanup_close_ int mount_node_fd = -EBADF; const char *options = NULL; @@ -930,6 +961,10 @@ static int dissect_image( return mount_node_fd; } + r = make_partition_devname(devname, diskseq, nr, flags, &n); + if (r < 0) + return r; + if (fstype) { t = strdup(fstype); if (!t) @@ -955,7 +990,7 @@ static int dissect_image( .rw = rw, .growfs = growfs, .architecture = type.arch, - .node = TAKE_PTR(node), + .node = TAKE_PTR(n), .fstype = TAKE_PTR(t), .label = TAKE_PTR(l), .uuid = id, @@ -982,16 +1017,14 @@ static int dissect_image( generic_nr = nr; generic_rw = true; generic_growfs = false; - generic_node = strdup(node); - if (!generic_node) - return -ENOMEM; + generic_node = TAKE_PTR(node); } break; case 0xEA: { /* Boot Loader Spec extended $BOOT partition */ _cleanup_close_ int mount_node_fd = -EBADF; - _cleanup_free_ char *o = NULL; + _cleanup_free_ char *o = NULL, *n = NULL; sd_id128_t id = SD_ID128_NULL; const char *options = NULL; @@ -1007,6 +1040,10 @@ static int dissect_image( (void) blkid_partition_get_uuid_id128(pp, &id); + r = make_partition_devname(devname, diskseq, nr, flags, &n); + if (r < 0) + return r; + options = mount_options_from_designator(mount_options, PARTITION_XBOOTLDR); if (options) { o = strdup(options); @@ -1020,7 +1057,7 @@ static int dissect_image( .rw = true, .growfs = false, .architecture = _ARCHITECTURE_INVALID, - .node = TAKE_PTR(node), + .node = TAKE_PTR(n), .uuid = id, .mount_options = TAKE_PTR(o), .mount_node_fd = TAKE_FD(mount_node_fd), @@ -1076,7 +1113,7 @@ static int dissect_image( /* If we didn't find a generic node, then we can't fix this up either */ if (generic_node) { _cleanup_close_ int mount_node_fd = -EBADF; - _cleanup_free_ char *o = NULL; + _cleanup_free_ char *o = NULL, *n = NULL; const char *options; if (FLAGS_SET(flags, DISSECT_IMAGE_PIN_PARTITION_DEVICES)) { @@ -1085,6 +1122,10 @@ static int dissect_image( return mount_node_fd; } + r = make_partition_devname(devname, diskseq, generic_nr, flags, &n); + if (r < 0) + return r; + options = mount_options_from_designator(mount_options, PARTITION_ROOT); if (options) { o = strdup(options); @@ -1099,7 +1140,7 @@ static int dissect_image( .growfs = generic_growfs, .partno = generic_nr, .architecture = _ARCHITECTURE_INVALID, - .node = TAKE_PTR(generic_node), + .node = TAKE_PTR(n), .uuid = generic_uuid, .mount_options = TAKE_PTR(o), .mount_node_fd = TAKE_FD(mount_node_fd), diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h index b65193f887..e9ab1f89a3 100644 --- a/src/shared/dissect-image.h +++ b/src/shared/dissect-image.h @@ -78,6 +78,7 @@ typedef enum DissectImageFlags { DISSECT_IMAGE_ADD_PARTITION_DEVICES = 1 << 20, /* Create partition devices via BLKPG_ADD_PARTITION */ DISSECT_IMAGE_PIN_PARTITION_DEVICES = 1 << 21, /* Open dissected partitions and decrypted partitions and pin them by fd */ DISSECT_IMAGE_RELAX_SYSEXT_CHECK = 1 << 22, /* Don't insist that the extension-release file name matches the image name */ + DISSECT_IMAGE_DISKSEQ_DEVNODE = 1 << 23, /* Prefer /dev/disk/by-diskseq/… device nodes */ } DissectImageFlags; struct DissectedImage {