repart: report vendor/model/subsystem fields in ListCandidateDevices

Prompted by: #39435
This commit is contained in:
Lennart Poettering
2025-11-01 22:01:35 +01:00
parent ea94a05f8a
commit 5f076e44fe
4 changed files with 87 additions and 2 deletions
+5 -1
View File
@@ -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;
}
+70
View File
@@ -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 {
+4
View File
@@ -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;
+8 -1
View File
@@ -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);