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