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,
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;
}
#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"
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) {
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;
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);
.symlinks = TAKE_PTR(list),
.diskseq = diskseq,
.size = size,
+ .model = TAKE_PTR(model),
+ .vendor = TAKE_PTR(vendor),
+ .subsystem = TAKE_PTR(subsystem),
};
} else {
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);