From: Lennart Poettering Date: Fri, 24 Oct 2025 15:18:51 +0000 (+0200) Subject: repart: report vendor/model/subsystem fields in ListCandidateDevices X-Git-Tag: v259-rc1~193^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5f076e44feb3f0b30dd88a4025b2e41860cabe6c;p=thirdparty%2Fsystemd.git repart: report vendor/model/subsystem fields in ListCandidateDevices Prompted by: #39435 --- diff --git a/src/repart/repart.c b/src/repart/repart.c index 2d6d7407251..6aab17ff0ab 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -10125,6 +10125,7 @@ static int vl_method_list_candidate_devices( BLOCKDEV_LIST_SHOW_SYMLINKS| BLOCKDEV_LIST_REQUIRE_PARTITION_SCANNING| BLOCKDEV_LIST_IGNORE_ZRAM| + BLOCKDEV_LIST_METADATA| (p.ignore_empty ? BLOCKDEV_LIST_IGNORE_EMPTY : 0)| (p.ignore_root ? BLOCKDEV_LIST_IGNORE_ROOT : 0), &l, @@ -10150,7 +10151,10 @@ static int vl_method_list_candidate_devices( SD_JSON_BUILD_PAIR_STRING("node", d->node), JSON_BUILD_PAIR_STRV_NON_EMPTY("symlinks", d->symlinks), JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("diskseq", d->diskseq, UINT64_MAX), - JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("sizeBytes", d->size, UINT64_MAX)); + JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("sizeBytes", d->size, UINT64_MAX), + JSON_BUILD_PAIR_STRING_NON_EMPTY("model", d->model), + JSON_BUILD_PAIR_STRING_NON_EMPTY("vendor", d->vendor), + JSON_BUILD_PAIR_STRING_NON_EMPTY("subsystem", d->subsystem)); if (r < 0) return r; } diff --git a/src/shared/blockdev-list.c b/src/shared/blockdev-list.c index 1a995235962..6897ea6bcad 100644 --- a/src/shared/blockdev-list.c +++ b/src/shared/blockdev-list.c @@ -8,6 +8,8 @@ #include "blockdev-util.h" #include "device-private.h" #include "device-util.h" +#include "errno-util.h" +#include "string-util.h" #include "strv.h" #include "terminal-util.h" @@ -16,6 +18,9 @@ void block_device_done(BlockDevice *d) { d->node = mfree(d->node); d->symlinks = strv_free(d->symlinks); + d->model = mfree(d->model); + d->vendor = mfree(d->vendor); + d->subsystem = mfree(d->subsystem); } void block_device_array_free(BlockDevice *d, size_t n_devices) { @@ -26,6 +31,61 @@ void block_device_array_free(BlockDevice *d, size_t n_devices) { free(d); } +static int blockdev_get_prop(sd_device *d, const char *prop1, const char *prop2, char **ret_value) { + int r, ret = 0; + + assert(d); + assert(prop1); + assert(ret_value); + + FOREACH_STRING(prop, prop1, prop2) { + const char *m = NULL; + r = sd_device_get_property_value(d, prop, &m); + if (r < 0 && r != -ENOENT) + RET_GATHER(ret, log_device_debug_errno(d, r, "Failed to acquire '%s' from device, ignoring: %m", prop)); + else if (!isempty(m)) + return strdup_to(ret_value, m); + } + + return ret < 0 ? ret : -ENOENT; +} + +static int blockdev_get_subsystem(sd_device *d, char **ret_subsystem) { + int r; + + assert(d); + assert(ret_subsystem); + + /* We prefer the explicitly set block device subsystem property, because if it is set it's generally + * the most useful. If it's not set we'll look for the subsystem of the first parent device that + * isn't of subsystem 'block'. The former covers 'virtual' block devices such as loopback, device + * mapper, zram, while the latter covers physical block devices such as USB or NVME. */ + + r = blockdev_get_prop(d, "ID_BLOCK_SUBSYSTEM", /* prop2= */ NULL, ret_subsystem); + if (r >= 0) + return r; + + int ret = r != -ENOENT ? r : 0; + sd_device *q = d; + for (;;) { + r = sd_device_get_parent(q, &q); + if (r < 0) { + if (r != -ENOENT) + RET_GATHER(ret, log_device_debug_errno(q, r, "Failed to get parent device, ignoring: %m")); + break; + } + + const char *s = NULL; + r = sd_device_get_subsystem(q, &s); + if (r < 0) + RET_GATHER(ret, log_device_debug_errno(q, r, "Failed to get subsystem of device, ignoring: %m")); + else if (!isempty(s) && !streq(s, "block")) + return strdup_to(ret_subsystem, s); + } + + return ret < 0 ? ret : -ENOENT; +} + int blockdev_list(BlockDevListFlags flags, BlockDevice **ret_devices, size_t *ret_n_devices) { _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; int r; @@ -128,6 +188,13 @@ int blockdev_list(BlockDevListFlags flags, BlockDevice **ret_devices, size_t *re strv_sort(list); } + _cleanup_free_ char *model = NULL, *vendor = NULL, *subsystem = NULL; + if (FLAGS_SET(flags, BLOCKDEV_LIST_METADATA)) { + (void) blockdev_get_prop(dev, "ID_MODEL_FROM_DATABASE", "ID_MODEL", &model); + (void) blockdev_get_prop(dev, "ID_VENDOR_FROM_DATABASE", "ID_VENDOR", &vendor); + (void) blockdev_get_subsystem(dev, &subsystem); + } + if (ret_devices) { uint64_t diskseq = UINT64_MAX; r = sd_device_get_diskseq(dev, &diskseq); @@ -146,6 +213,9 @@ int blockdev_list(BlockDevListFlags flags, BlockDevice **ret_devices, size_t *re .symlinks = TAKE_PTR(list), .diskseq = diskseq, .size = size, + .model = TAKE_PTR(model), + .vendor = TAKE_PTR(vendor), + .subsystem = TAKE_PTR(subsystem), }; } else { diff --git a/src/shared/blockdev-list.h b/src/shared/blockdev-list.h index f1f1bc99497..845f336be5b 100644 --- a/src/shared/blockdev-list.h +++ b/src/shared/blockdev-list.h @@ -10,11 +10,15 @@ typedef enum BlockDevListFlags { BLOCKDEV_LIST_REQUIRE_LUKS = 1 << 3, /* Only consider block devices with LUKS superblocks */ BLOCKDEV_LIST_IGNORE_ROOT = 1 << 4, /* Ignore the block device we are currently booted from */ BLOCKDEV_LIST_IGNORE_EMPTY = 1 << 5, /* Ignore disks of zero size (usually drives without a medium) */ + BLOCKDEV_LIST_METADATA = 1 << 6, /* Fill in model, vendor, subsystem */ } BlockDevListFlags; typedef struct BlockDevice { char *node; char **symlinks; + char *model; + char *vendor; + char *subsystem; uint64_t diskseq; uint64_t size; /* in bytes */ } BlockDevice; diff --git a/src/shared/varlink-io.systemd.Repart.c b/src/shared/varlink-io.systemd.Repart.c index ba10a669992..53f5563d825 100644 --- a/src/shared/varlink-io.systemd.Repart.c +++ b/src/shared/varlink-io.systemd.Repart.c @@ -72,7 +72,14 @@ static SD_VARLINK_DEFINE_METHOD( SD_VARLINK_FIELD_COMMENT("The Linux kernel disk sequence number identifying the medium."), SD_VARLINK_DEFINE_OUTPUT(diskseq, SD_VARLINK_INT, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("The size of the block device in bytes."), - SD_VARLINK_DEFINE_OUTPUT(sizeBytes, SD_VARLINK_INT, SD_VARLINK_NULLABLE)); + SD_VARLINK_DEFINE_OUTPUT(sizeBytes, SD_VARLINK_INT, SD_VARLINK_NULLABLE), + SD_VARLINK_FIELD_COMMENT("The device vendor string if known"), + SD_VARLINK_DEFINE_OUTPUT(vendor, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), + SD_VARLINK_FIELD_COMMENT("The device model string if known"), + SD_VARLINK_DEFINE_OUTPUT(model, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), + SD_VARLINK_FIELD_COMMENT("The subsystem the block device belongs to if known"), + SD_VARLINK_DEFINE_OUTPUT(subsystem, SD_VARLINK_STRING, SD_VARLINK_NULLABLE)); + static SD_VARLINK_DEFINE_ERROR(NoCandidateDevices); static SD_VARLINK_DEFINE_ERROR(ConflictingDiskLabelPresent);