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
+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 {