]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Add --json switch to udevadm info
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Thu, 12 Oct 2023 09:02:49 +0000 (11:02 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Mon, 16 Oct 2023 11:01:54 +0000 (13:01 +0200)
This allows getting the udevadm info --export-db and query "all" output
as JSON.

man/udevadm.xml
src/udev/udevadm-info.c
test/units/testsuite-17.10.sh

index 66d58a4d0ce46f064fddd745d6e5452b394f93d8..3bc62667105be52ae0245fa2f19643fafb8abf80 100644 (file)
           </listitem>
         </varlistentry>
 
+        <xi:include href="standard-options.xml" xpointer="json" />
         <xi:include href="standard-options.xml" xpointer="help" />
         <xi:include href="standard-options.xml" xpointer="no-pager" />
       </variablelist>
index ae7251cbcc1a0748f17d2d269791af5db192f862..22e5496c40c3cf2342d6aa55d5d0efb7a58c89fc 100644 (file)
 #include "device-enumerator-private.h"
 #include "device-private.h"
 #include "device-util.h"
+#include "devnum-util.h"
 #include "dirent-util.h"
 #include "errno-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "glyph-util.h"
+#include "json.h"
 #include "pager.h"
+#include "parse-argument.h"
 #include "sort-util.h"
 #include "static-destruct.h"
 #include "string-table.h"
@@ -35,6 +38,7 @@ typedef enum ActionType {
         ACTION_ATTRIBUTE_WALK,
         ACTION_DEVICE_ID_FILE,
         ACTION_TREE,
+        ACTION_EXPORT,
 } ActionType;
 
 typedef enum QueryType {
@@ -52,6 +56,7 @@ static bool arg_value = false;
 static const char *arg_export_prefix = NULL;
 static usec_t arg_wait_for_initialization_timeout = 0;
 PagerFlags arg_pager_flags = 0;
+static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
 
 /* Put a limit on --tree descent level to not exhaust our stack */
 #define TREE_DEPTH_MAX 64
@@ -260,6 +265,39 @@ static int print_record(sd_device *device, const char *prefix) {
         return 0;
 }
 
+static int record_to_json(sd_device *device, JsonVariant **ret) {
+        _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
+        const char *str;
+        int r;
+
+        assert(device);
+        assert(ret);
+
+        /* We don't show any shorthand fields here as done in print_record() except for SYSNAME and SYSNUM as
+         * all the other ones have a matching property which will already be included. */
+
+        if (sd_device_get_sysname(device, &str) >= 0) {
+                r = json_variant_set_field_string(&v, "SYSNAME", str);
+                if (r < 0)
+                        return r;
+        }
+
+        if (sd_device_get_sysnum(device, &str) >= 0) {
+                r = json_variant_set_field_string(&v, "SYSNUM", str);
+                if (r < 0)
+                        return r;
+        }
+
+        FOREACH_DEVICE_PROPERTY(device, key, val) {
+                r = json_variant_set_field_string(&v, key, val);
+                if (r < 0)
+                        return r;
+        }
+
+        *ret = TAKE_PTR(v);
+        return 0;
+}
+
 static int stat_device(const char *name, bool export, const char *prefix) {
         struct stat statbuf;
 
@@ -300,7 +338,17 @@ static int export_devices(void) {
         pager_open(arg_pager_flags);
 
         FOREACH_DEVICE_AND_SUBSYSTEM(e, d)
-                (void) print_record(d, NULL);
+                if (arg_json_format_flags & JSON_FORMAT_OFF)
+                        (void) print_record(d, NULL);
+                else {
+                        _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
+
+                        r = record_to_json(d, &v);
+                        if (r < 0)
+                                return r;
+
+                        (void) json_variant_dump(v, arg_json_format_flags, stdout, NULL);
+                }
 
         return 0;
 }
@@ -466,7 +514,19 @@ static int query_device(QueryType query, sd_device* device) {
                 return 0;
 
         case QUERY_ALL:
-                return print_record(device, NULL);
+                if (arg_json_format_flags & JSON_FORMAT_OFF)
+                        return print_record(device, NULL);
+                else {
+                        _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
+
+                        r = record_to_json(device, &v);
+                        if (r < 0)
+                                return r;
+
+                        (void) json_variant_dump(v, arg_json_format_flags, stdout, NULL);
+                }
+
+                return 0;
 
         default:
                 assert_not_reached();
@@ -499,7 +559,8 @@ static int help(void) {
                "  -c --cleanup-db             Clean up the udev database\n"
                "  -w --wait-for-initialization[=SECONDS]\n"
                "                              Wait for device to be initialized\n"
-               "     --no-pager               Do not pipe output into a pager\n",
+               "     --no-pager               Do not pipe output into a pager\n"
+               "     --json=pretty|short|off  Generate JSON output\n",
                program_invocation_short_name);
 
         return 0;
@@ -671,6 +732,7 @@ int info_main(int argc, char *argv[], void *userdata) {
                 ARG_PROPERTY = 0x100,
                 ARG_VALUE,
                 ARG_NO_PAGER,
+                ARG_JSON,
         };
 
         static const struct option options[] = {
@@ -691,6 +753,7 @@ int info_main(int argc, char *argv[], void *userdata) {
                 { "version",                 no_argument,       NULL, 'V'          },
                 { "wait-for-initialization", optional_argument, NULL, 'w'          },
                 { "no-pager",                no_argument,       NULL, ARG_NO_PAGER },
+                { "json",                    required_argument, NULL, ARG_JSON     },
                 {}
         };
 
@@ -761,7 +824,8 @@ int info_main(int argc, char *argv[], void *userdata) {
                         action = ACTION_TREE;
                         break;
                 case 'e':
-                        return export_devices();
+                        action = ACTION_EXPORT;
+                        break;
                 case 'c':
                         cleanup_db();
                         return 0;
@@ -787,6 +851,13 @@ int info_main(int argc, char *argv[], void *userdata) {
                 case ARG_NO_PAGER:
                         arg_pager_flags |= PAGER_DISABLE;
                         break;
+
+                case ARG_JSON:
+                        r = parse_json_argument(optarg, &arg_json_format_flags);
+                        if (r <= 0)
+                                return r;
+                        break;
+
                 case '?':
                         return -EINVAL;
                 default:
@@ -801,6 +872,9 @@ int info_main(int argc, char *argv[], void *userdata) {
                 return stat_device(name, arg_export, arg_export_prefix);
         }
 
+        if (action == ACTION_EXPORT)
+                return export_devices();
+
         r = strv_extend_strv(&devices, argv + optind, false);
         if (r < 0)
                 return log_error_errno(r, "Failed to build argument list: %m");
index 2df4dcfb29f4b1725561035b702cf3fe0efc411f..5b319bca913843ec215da8f3223b00b73355e893 100755 (executable)
@@ -57,6 +57,9 @@ udevadm info --property DEVNAME --value /sys/class/net/$netdev
 udevadm info --property HELLO /sys/class/net/$netdev
 udevadm info -p class/net/$netdev
 udevadm info -p /class/net/$netdev
+udevadm info --json=off -p class/net/$netdev
+udevadm info --json=pretty -p class/net/$netdev | jq .
+udevadm info --json=short -p class/net/$netdev | jq .
 udevadm info -n null
 udevadm info -q all /sys/class/net/$netdev
 udevadm info -q name /dev/null
@@ -74,6 +77,9 @@ udevadm info -x -q path /sys/class/net/$netdev
 udevadm info -P TEST_ /sys/class/net/$netdev
 udevadm info -d /dev/null
 udevadm info -e >/dev/null
+udevadm info -e --json=off >/dev/null
+udevadm info -e --json=pretty | jq . >/dev/null
+udevadm info -e --json=short | jq . >/dev/null
 # udevadm info -c
 udevadm info -w /sys/class/net/$netdev
 udevadm info --wait-for-initialization=5 /sys/class/net/$netdev