repart: report vendor/model/subsystem fields in ListCandidateDevices
Prompted by: #39435
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user