]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
repart: report vendor/model/subsystem fields in ListCandidateDevices
authorLennart Poettering <lennart@poettering.net>
Fri, 24 Oct 2025 15:18:51 +0000 (17:18 +0200)
committerLennart Poettering <lennart@poettering.net>
Sat, 1 Nov 2025 21:01:35 +0000 (22:01 +0100)
Prompted by: #39435

src/repart/repart.c
src/shared/blockdev-list.c
src/shared/blockdev-list.h
src/shared/varlink-io.systemd.Repart.c

index 2d6d74072519942db4ade635f66bcb2232c3d9e0..6aab17ff0ab1bf2f0a833b3b4860e8c28155c4fb 100644 (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;
         }
index 1a995235962fff4a0ddc2a05df781dddda4579d8..6897ea6bcad0f4f1edab0aff795398ba9a900591 100644 (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 {
index f1f1bc99497afe0f13d1633aabd2c3ee723b8951..845f336be5b654d9e676671e36c6a0f894b8c4d4 100644 (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;
index ba10a66999242775cde5fa78b80a6683c80a68ad..53f5563d825e648727dc6876203ec55e6a822b1c 100644 (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);