]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #11107 from keszybz/udevadm-info-args
authorLennart Poettering <lennart@poettering.net>
Tue, 11 Dec 2018 11:12:58 +0000 (12:12 +0100)
committerGitHub <noreply@github.com>
Tue, 11 Dec 2018 11:12:58 +0000 (12:12 +0100)
Allow multiple args in udevadm info

man/udevadm.xml
src/udev/udevadm-info.c
src/udev/udevadm-util.c

index a63a92cef26f1d7ff8f1a0f5e2df0ab411c67cb7..44be7b3f894b5117dc5f5bdf152e2e1d16ab72c7 100644 (file)
 
     <refsect2><title>udevadm info
       <arg choice="opt"><replaceable>options</replaceable></arg>
-      <arg choice="opt"><replaceable>devpath</replaceable>|<replaceable>file</replaceable></arg>
+      <arg choice="opt" rep="repeat"><replaceable>devpath</replaceable>|<replaceable>file</replaceable>|<replaceable>unit</replaceable></arg>
     </title>
 
-      <para>Queries the udev database for device information
-      stored in the udev database. It can also query the properties
-      of a device from its sysfs representation to help creating udev
-      rules that match this device.</para>
+      <para>Query the udev database for device information.</para>
+
+      <para>Positional arguments should be used to specify one or more devices. Each one may be a device name
+      (in which case it must start with <filename>/dev/</filename>), a sys path (in which case it must start
+      with <filename>/sys/</filename>), or a systemd device unit name (in which case it must end with
+      <literal>.device</literal>, see
+      <citerefentry><refentrytitle>systemd.device</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
+      </para>
+
       <variablelist>
         <varlistentry>
           <term><option>-q</option></term>
           <term><option>--query=<replaceable>TYPE</replaceable></option></term>
           <listitem>
-            <para>Query the database for the specified type of device
-            data. It needs the <option>--path</option> or
-            <option>--name</option> to identify the specified device.
+            <para>Query the database for the specified type of device data.
             Valid <replaceable>TYPE</replaceable>s are:
             <constant>name</constant>, <constant>symlink</constant>,
             <constant>path</constant>, <constant>property</constant>,
             <constant>all</constant>.</para>
           </listitem>
         </varlistentry>
+
         <varlistentry>
           <term><option>-p</option></term>
           <term><option>--path=<replaceable>DEVPATH</replaceable></option></term>
           <listitem>
-            <para>The <filename>/sys</filename> path of the device to
-            query, e.g.
-            <filename><optional>/sys</optional>/class/block/sda</filename>.
-            Note that this option usually is not very useful, since
-            <command>udev</command> can guess the type of the
-            argument, so <command>udevadm info
-            --path=/class/block/sda</command> is equivalent to
-            <command>udevadm info /sys/class/block/sda</command>.</para>
+            <para>The <filename>/sys</filename> path of the device to query, e.g.
+            <filename><optional>/sys</optional>/class/block/sda</filename>. This option is an alternative to
+            the positional argument with a <filename>/sys/</filename> prefix. <command>udevadm info
+            --path=/class/block/sda</command> is equivalent to <command>udevadm info
+            /sys/class/block/sda</command>.</para>
           </listitem>
         </varlistentry>
         <varlistentry>
           <term><option>--name=<replaceable>FILE</replaceable></option></term>
           <listitem>
             <para>The name of the device node or a symlink to query,
-            e.g. <filename><optional>/dev</optional>/sda</filename>.
-            Note that this option usually is not very useful, since
-            <command>udev</command> can guess the type of the
-            argument, so <command>udevadm info --name=sda</command> is
-            equivalent to <command>udevadm info /dev/sda</command>.</para>
+            e.g. <filename><optional>/dev</optional>/sda</filename>. This option is an alternative to the
+            positional argument with a <filename>/dev/</filename> prefix. <command>udevadm info
+            --name=sda</command> is equivalent to <command>udevadm info /dev/sda</command>.</para>
           </listitem>
         </varlistentry>
         <varlistentry>
 
         <xi:include href="standard-options.xml" xpointer="help" />
       </variablelist>
-
-      <para>In addition, an optional positional argument can be used
-      to specify a device name or a sys path. It must start with
-      <filename>/dev</filename> or <filename>/sys</filename>
-      respectively.</para>
     </refsect2>
 
     <refsect2><title>udevadm trigger
       <arg choice="opt"><replaceable>options</replaceable></arg>
-      <arg choice="opt" rep="repeat"><replaceable>devpath</replaceable>|<replaceable>file</replaceable></arg></title>
+      <arg choice="opt" rep="repeat"><replaceable>devpath</replaceable>|<replaceable>file</replaceable>|<replaceable>unit</replaceable></arg>
+      </title>
       <para>Request device events from the kernel. Primarily used to replay events at system coldplug time.</para>
+
+      <para>Takes one or more device specifications as arguments. See the description of <command>info</command>
+      above.</para>
+
       <variablelist>
         <varlistentry>
           <term><option>-v</option></term>
index 1894362828fcac12d704b6d345cb1ee5e9482a8a..d141bc74b2a10fc91d255c687b9659cfeaf6504c 100644 (file)
 #include "udevadm.h"
 #include "udevadm-util.h"
 
+typedef enum ActionType {
+        ACTION_QUERY,
+        ACTION_ATTRIBUTE_WALK,
+        ACTION_DEVICE_ID_FILE,
+} ActionType;
+
+typedef enum QueryType {
+        QUERY_NAME,
+        QUERY_PATH,
+        QUERY_SYMLINK,
+        QUERY_PROPERTY,
+        QUERY_ALL,
+} QueryType;
+
+static bool arg_root = false;
+static bool arg_export = false;
+static const char *arg_export_prefix = NULL;
+
 static bool skip_attribute(const char *name) {
         static const char* const skip[] = {
                 "uevent",
@@ -62,7 +80,7 @@ static void print_all_attributes(sd_device *device, const char *key) {
 
                 printf("    %s{%s}==\"%s\"\n", key, name, value);
         }
-        printf("\n");
+        puts("");
 }
 
 static int print_device_chain(sd_device *device) {
@@ -106,26 +124,31 @@ static int print_device_chain(sd_device *device) {
         return 0;
 }
 
-static void print_record(sd_device *device) {
+static int print_record(sd_device *device) {
         const char *str, *val;
         int i;
 
         (void) sd_device_get_devpath(device, &str);
         printf("P: %s\n", str);
 
-        if (sd_device_get_devname(device, &str) >= 0)
-                printf("N: %s\n", str + STRLEN("/dev/"));
+        if (sd_device_get_devname(device, &str) >= 0) {
+                assert_se(val = path_startswith(str, "/dev/"));
+                printf("N: %s\n", val);
+        }
 
         if (device_get_devlink_priority(device, &i) >= 0)
                 printf("L: %i\n", i);
 
-        FOREACH_DEVICE_DEVLINK(device, str)
-                printf("S: %s\n", str + STRLEN("/dev/"));
+        FOREACH_DEVICE_DEVLINK(device, str) {
+                assert_se(val = path_startswith(str, "/dev/"));
+                printf("S: %s\n", val);
+        }
 
         FOREACH_DEVICE_PROPERTY(device, str, val)
                 printf("E: %s=%s\n", str, val);
 
-        printf("\n");
+        puts("");
+        return 0;
 }
 
 static int stat_device(const char *name, bool export, const char *prefix) {
@@ -223,8 +246,69 @@ static void cleanup_db(void) {
                 cleanup_dir(dir5, 0, 1);
 }
 
-static int help(void) {
+static int query_device(QueryType query, sd_device* device) {
+        int r;
+
+        assert(device);
+
+        switch(query) {
+        case QUERY_NAME: {
+                const char *node;
+
+                r = sd_device_get_devname(device, &node);
+                if (r < 0)
+                        return log_error_errno(r, "No device node found: %m");
+
+                if (!arg_root)
+                        assert_se(node = path_startswith(node, "/dev/"));
+                printf("%s\n", node);
+                return 0;
+        }
+
+        case QUERY_SYMLINK: {
+                const char *devlink, *prefix = "";
+
+                FOREACH_DEVICE_DEVLINK(device, devlink) {
+                        if (!arg_root)
+                                assert_se(devlink = path_startswith(devlink, "/dev/"));
+                        printf("%s%s", prefix, devlink);
+                        prefix = " ";
+                }
+                puts("");
+                return 0;
+        }
+
+        case QUERY_PATH: {
+                const char *devpath;
+
+                r = sd_device_get_devpath(device, &devpath);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get device path: %m");
 
+                printf("%s\n", devpath);
+                return 0;
+        }
+
+        case QUERY_PROPERTY: {
+                const char *key, *value;
+
+                FOREACH_DEVICE_PROPERTY(device, key, value)
+                        if (arg_export)
+                                printf("%s%s='%s'\n", strempty(arg_export_prefix), key, value);
+                        else
+                                printf("%s=%s\n", key, value);
+                return 0;
+        }
+
+        case QUERY_ALL:
+                return print_record(device);
+        }
+
+        assert_not_reached("unknown query type");
+        return 0;
+}
+
+static int help(void) {
         printf("%s info [OPTIONS] [DEVPATH|FILE]\n\n"
                "Query sysfs or the udev database.\n\n"
                "  -h --help                   Print this message\n"
@@ -251,10 +335,8 @@ static int help(void) {
 }
 
 int info_main(int argc, char *argv[], void *userdata) {
-        _cleanup_(sd_device_unrefp) sd_device *device = NULL;
-        bool root = false, export = false;
+        _cleanup_strv_free_ char **devices = NULL;
         _cleanup_free_ char *name = NULL;
-        const char *export_prefix = NULL;
         int c, r;
 
         static const struct option options[] = {
@@ -273,42 +355,26 @@ int info_main(int argc, char *argv[], void *userdata) {
                 {}
         };
 
-        enum action_type {
-                ACTION_QUERY,
-                ACTION_ATTRIBUTE_WALK,
-                ACTION_DEVICE_ID_FILE,
-        } action = ACTION_QUERY;
-
-        enum query_type {
-                QUERY_NAME,
-                QUERY_PATH,
-                QUERY_SYMLINK,
-                QUERY_PROPERTY,
-                QUERY_ALL,
-        } query = QUERY_ALL;
+        ActionType action = ACTION_QUERY;
+        QueryType query = QUERY_ALL;
 
         while ((c = getopt_long(argc, argv, "aced:n:p:q:rxP:RVh", options, NULL)) >= 0)
                 switch (c) {
                 case 'n':
-                        if (device) {
-                                log_error("device already specified");
-                                return -EINVAL;
-                        }
+                case 'p': {
+                        const char *prefix = c == 'n' ? "/dev/" : "/sys/";
+                        char *path;
 
-                        r = find_device(optarg, "/dev/", &device);
-                        if (r < 0)
-                                return log_error_errno(r, "device node not found: %m");
-                        break;
-                case 'p':
-                        if (device) {
-                                log_error("device already specified");
-                                return -EINVAL;
-                        }
+                        path = path_join(path_startswith(optarg, prefix) ? NULL : prefix, optarg);
+                        if (!path)
+                                return log_oom();
 
-                        r = find_device(optarg, "/sys", &device);
+                        r = strv_consume(&devices, path);
                         if (r < 0)
-                                return log_error_errno(r, "syspath not found: %m");
+                                return log_oom();
                         break;
+                }
+
                 case 'q':
                         action = ACTION_QUERY;
                         if (streq(optarg, "property") || streq(optarg, "env"))
@@ -327,7 +393,7 @@ int info_main(int argc, char *argv[], void *userdata) {
                         }
                         break;
                 case 'r':
-                        root = true;
+                        arg_root = true;
                         break;
                 case 'd':
                         action = ACTION_DEVICE_ID_FILE;
@@ -344,10 +410,10 @@ int info_main(int argc, char *argv[], void *userdata) {
                         cleanup_db();
                         return 0;
                 case 'x':
-                        export = true;
+                        arg_export = true;
                         break;
                 case 'P':
-                        export_prefix = optarg;
+                        arg_export_prefix = optarg;
                         break;
                 case 'V':
                         return print_version();
@@ -359,94 +425,44 @@ int info_main(int argc, char *argv[], void *userdata) {
                         assert_not_reached("Unknown option");
                 }
 
-        switch (action) {
-        case ACTION_QUERY:
-                if (!device) {
-                        if (!argv[optind]) {
-                                help();
-                                return -EINVAL;
-                        }
-                        r = find_device(argv[optind], NULL, &device);
-                        if (r < 0)
-                                return log_error_errno(r, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected: %m");
-                }
-
-                switch(query) {
-                case QUERY_NAME: {
-                        const char *node;
-
-                        r = sd_device_get_devname(device, &node);
-                        if (r < 0)
-                                return log_error_errno(r, "no device node found: %m");
-
-                        if (root)
-                                printf("%s\n", node);
-                        else
-                                printf("%s\n", node + STRLEN("/dev/"));
-                        break;
-                }
-                case QUERY_SYMLINK: {
-                        const char *devlink;
-                        bool first = true;
-
-                        FOREACH_DEVICE_DEVLINK(device, devlink) {
-                                if (!first)
-                                        printf(" ");
-                                if (root)
-                                        printf("%s", devlink);
-                                else
-                                        printf("%s", devlink + STRLEN("/dev/"));
-
-                                first = false;
-                        }
-                        printf("\n");
-                        break;
-                }
-                case QUERY_PATH: {
-                        const char *devpath;
-
-                        r = sd_device_get_devpath(device, &devpath);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to get device path: %m");
 
-                        printf("%s\n", devpath);
-                        return 0;
-                }
-                case QUERY_PROPERTY: {
-                        const char *key, *value;
-
-                        FOREACH_DEVICE_PROPERTY(device, key, value)
-                                if (export)
-                                        printf("%s%s='%s'\n", strempty(export_prefix), key, value);
-                                else
-                                        printf("%s=%s\n", key, value);
+        if (action == ACTION_DEVICE_ID_FILE) {
+                if (argv[optind])
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "Positional arguments are not allowed with -d/--device-id-of-file.");
+                assert(name);
+                return stat_device(name, arg_export, arg_export_prefix);
+        }
 
-                        break;
-                }
-                case QUERY_ALL:
-                        print_record(device);
-                        break;
-                default:
-                        assert_not_reached("unknown query type");
-                }
-                break;
-        case ACTION_ATTRIBUTE_WALK:
-                if (!device && argv[optind]) {
-                        r = find_device(argv[optind], NULL, &device);
-                        if (r < 0)
-                                return log_error_errno(r, "Unknown device, absolute path in /dev/ or /sys expected: %m");
-                }
-                if (!device) {
-                        log_error("Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.");
-                        return -EINVAL;
-                }
-                print_device_chain(device);
-                break;
-        case ACTION_DEVICE_ID_FILE:
-                r = stat_device(name, export, export_prefix);
+        r = strv_extend_strv(&devices, argv + optind, false);
+        if (r < 0)
+                return log_error_errno(r, "Failed to build argument list: %m");
+
+        if (strv_isempty(devices))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "A device name or path is required");
+        if (action == ACTION_ATTRIBUTE_WALK && strv_length(devices) > 1)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Only one device may be specified with -a/--attribute-walk");
+
+        char **p;
+        STRV_FOREACH(p, devices) {
+                _cleanup_(sd_device_unrefp) sd_device *device = NULL;
+
+                r = find_device(*p, NULL, &device);
+                if (r == -EINVAL)
+                        return log_error_errno(r, "Bad argument \"%s\", expected an absolute path in /dev/ or /sys or a unit name: %m", *p);
+                if (r < 0)
+                        return log_error_errno(r, "Unknown device \"%s\": %m",  *p);
+
+                if (action == ACTION_QUERY)
+                        r = query_device(query, device);
+                else if (action == ACTION_ATTRIBUTE_WALK)
+                        r = print_device_chain(device);
+                else
+                        assert_not_reached("Unknown action");
                 if (r < 0)
                         return r;
-                break;
         }
 
         return 0;
index ef0dc564ce6a50509c818ab000e24b7b6a4fe07e..557982b23dfa896b9c5681c17e2edda0110bb936 100644 (file)
@@ -6,18 +6,31 @@
 #include "device-private.h"
 #include "path-util.h"
 #include "udevadm-util.h"
+#include "unit-name.h"
 
 int find_device(const char *id, const char *prefix, sd_device **ret) {
-        _cleanup_free_ char *buf = NULL;
+        _cleanup_free_ char *path = NULL;
+        int r;
 
         assert(id);
         assert(ret);
 
-        if (prefix && !path_startswith(id, prefix)) {
-                buf = path_join(prefix, id);
-                if (!buf)
-                        return -ENOMEM;
-                id = buf;
+        if (prefix) {
+                if (!path_startswith(id, prefix)) {
+                        id = path = path_join(prefix, id);
+                        if (!path)
+                                return -ENOMEM;
+                }
+        } else {
+                /* In cases where the argument is generic (no prefix specified),
+                 * check if the argument looks like a device unit name. */
+                if (unit_name_is_valid(id, UNIT_NAME_PLAIN) &&
+                    unit_name_to_type(id) == UNIT_DEVICE) {
+                        r = unit_name_to_path(id, &path);
+                        if (r < 0)
+                                return log_debug_errno(r, "Failed to convert \"%s\" to a device path: %m", id);
+                        id = path;
+                }
         }
 
         if (path_startswith(id, "/sys/"))