]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udevadm-info: support json output for --attribute-walk 33942/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 5 Aug 2024 03:29:46 +0000 (12:29 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 5 Aug 2024 20:22:10 +0000 (05:22 +0900)
Closes #33852.

src/udev/udevadm-info.c
test/units/TEST-17-UDEV.10.sh

index 1a0e2656ce0e8a0fa2c2397b1be62536997f2efc..824b6fc72682cbe5019612112046a67000065e8d 100644 (file)
@@ -186,6 +186,107 @@ static int print_device_chain(sd_device *device) {
         return 0;
 }
 
+static int print_all_attributes_in_json(sd_device *device, bool is_parent) {
+        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL, *w = NULL;
+        _cleanup_free_ SysAttr *sysattrs = NULL;
+        const char *value;
+        size_t n_items = 0;
+        int r;
+
+        assert(device);
+
+        value = NULL;
+        (void) sd_device_get_devpath(device, &value);
+        r = sd_json_variant_set_field_string(&v, "DEVPATH", value);
+        if (r < 0)
+                return r;
+
+        value = NULL;
+        (void) sd_device_get_sysname(device, &value);
+        r = sd_json_variant_set_field_string(&v, is_parent ? "KERNELS" : "KERNEL", value);
+        if (r < 0)
+                return r;
+
+        value = NULL;
+        (void) sd_device_get_subsystem(device, &value);
+        r = sd_json_variant_set_field_string(&v, is_parent ? "SUBSYSTEMS" : "SUBSYSTEM", value);
+        if (r < 0)
+                return r;
+
+        value = NULL;
+        (void) sd_device_get_driver(device, &value);
+        r = sd_json_variant_set_field_string(&v, is_parent ? "DRIVERS" : "DRIVER", value);
+        if (r < 0)
+                return r;
+
+        FOREACH_DEVICE_SYSATTR(device, name) {
+                size_t len;
+
+                if (skip_attribute(name))
+                        continue;
+
+                r = sd_device_get_sysattr_value(device, name, &value);
+                if (r >= 0) {
+                        /* skip any values that look like a path */
+                        if (value[0] == '/')
+                                continue;
+
+                        /* skip nonprintable attributes */
+                        len = strlen(value);
+                        while (len > 0 && isprint((unsigned char) value[len-1]))
+                                len--;
+                        if (len > 0)
+                                continue;
+
+                } else if (ERRNO_IS_PRIVILEGE(r))
+                        value = "(not readable)";
+                else
+                        continue;
+
+                if (!GREEDY_REALLOC(sysattrs, n_items + 1))
+                        return log_oom();
+
+                sysattrs[n_items] = (SysAttr) {
+                        .name = name,
+                        .value = value,
+                };
+                n_items++;
+        }
+
+        typesafe_qsort(sysattrs, n_items, sysattr_compare);
+
+        FOREACH_ARRAY(i, sysattrs, n_items) {
+                r = sd_json_variant_set_field_string(&w, i->name, i->value);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_json_variant_set_field(&v, is_parent ? "ATTRS" : "ATTR", w);
+        if (r < 0)
+                return r;
+
+        return sd_json_variant_dump(v, arg_json_format_flags, stdout, NULL);
+}
+
+static int print_device_chain_in_json(sd_device *device) {
+        sd_device *child, *parent;
+        int r;
+
+        assert(device);
+
+        r = print_all_attributes_in_json(device, /* is_parent = */ false);
+        if (r < 0)
+                return r;
+
+        for (child = device; sd_device_get_parent(child, &parent) >= 0; child = parent) {
+                r = print_all_attributes_in_json(parent, /* is_parent = */ true);
+                if (r < 0)
+                        return r;
+        }
+
+        return 0;
+}
+
 static int print_record(sd_device *device, const char *prefix) {
         const char *str, *subsys;
         dev_t devnum;
@@ -1108,9 +1209,12 @@ int info_main(int argc, char *argv[], void *userdata) {
 
                 if (action == ACTION_QUERY)
                         r = query_device(query, device);
-                else if (action == ACTION_ATTRIBUTE_WALK)
-                        r = print_device_chain(device);
-                else if (action == ACTION_TREE)
+                else if (action == ACTION_ATTRIBUTE_WALK) {
+                        if (arg_json_format_flags & SD_JSON_FORMAT_OFF)
+                                r = print_device_chain(device);
+                        else
+                                r = print_device_chain_in_json(device);
+                } else if (action == ACTION_TREE)
                         r = print_tree(device);
                 else
                         assert_not_reached();
index a2b8b14d0c2a564c05a85a3e4b7e97869351bf22..1808e1975b6a516f7c3fc823991e8b4fb4a0fdde 100755 (executable)
@@ -70,6 +70,9 @@ udevadm info -q name -r /dev/null
 udevadm info --query symlink --root /sys/class/net/$netdev
 (! udevadm info -q hello -r /sys/class/net/$netdev)
 udevadm info -a /sys/class/net/$netdev
+udevadm info -a --json=off /sys/class/net/$netdev
+udevadm info -a --json=pretty /sys/class/net/$netdev | jq . >/dev/null
+udevadm info -a --json=short /sys/class/net/$netdev | jq . >/dev/null
 udevadm info -t >/dev/null
 udevadm info --tree /sys/class/net/$netdev
 udevadm info -x /sys/class/net/$netdev