X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fsystemd.git;a=blobdiff_plain;f=src%2Fudev%2Fudevadm-info.c;h=ae6d8caf54e02c39c4b5f4245b5523cc9713eb97;hp=4f7a4a388cc9348d5e5516921b79873d4af345f0;hb=e7e954243a17cceb5278aac6249ee0dcc119b1eb;hpb=668e7c0cfdf8cfe0bf545507e8c6bc54e44cbc97 diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c index 4f7a4a388cc..ae6d8caf54e 100644 --- a/src/udev/udevadm-info.c +++ b/src/udev/udevadm-info.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include @@ -18,9 +17,12 @@ #include "device-util.h" #include "dirent-util.h" #include "fd-util.h" +#include "sort-util.h" +#include "string-table.h" #include "string-util.h" -#include "udevadm.h" +#include "udev-util.h" #include "udevadm-util.h" +#include "udevadm.h" typedef enum ActionType { ACTION_QUERY, @@ -39,53 +41,93 @@ typedef enum QueryType { static bool arg_root = false; static bool arg_export = false; static const char *arg_export_prefix = NULL; +static usec_t arg_wait_for_initialization_timeout = 0; static bool skip_attribute(const char *name) { - static const char* const skip[] = { - "uevent", - "dev", - "modalias", - "resource", - "driver", - "subsystem", - "module", - }; - unsigned i; + /* Those are either displayed separately or should not be shown at all. */ + return STR_IN_SET(name, + "uevent", + "dev", + "modalias", + "resource", + "driver", + "subsystem", + "module"); +} - for (i = 0; i < ELEMENTSOF(skip); i++) - if (streq(name, skip[i])) - return true; - return false; +typedef struct SysAttr { + const char *name; + const char *value; +} SysAttr; + +static int sysattr_compare(const SysAttr *a, const SysAttr *b) { + return strcmp(a->name, b->name); } -static void print_all_attributes(sd_device *device, const char *key) { +static int print_all_attributes(sd_device *device, bool is_parent) { + _cleanup_free_ SysAttr *sysattrs = NULL; + size_t n_items = 0, n_allocated = 0; const char *name, *value; - FOREACH_DEVICE_PROPERTY(device, name, value) { + value = NULL; + (void) sd_device_get_devpath(device, &value); + printf(" looking at %sdevice '%s':\n", is_parent ? "parent " : "", strempty(value)); + + value = NULL; + (void) sd_device_get_sysname(device, &value); + printf(" %s==\"%s\"\n", is_parent ? "KERNELS" : "KERNEL", strempty(value)); + + value = NULL; + (void) sd_device_get_subsystem(device, &value); + printf(" %s==\"%s\"\n", is_parent ? "SUBSYSTEMS" : "SUBSYSTEM", strempty(value)); + + value = NULL; + (void) sd_device_get_driver(device, &value); + printf(" %s==\"%s\"\n", is_parent ? "DRIVERS" : "DRIVER", strempty(value)); + + FOREACH_DEVICE_SYSATTR(device, name) { size_t len; if (skip_attribute(name)) continue; + if (sd_device_get_sysattr_value(device, name, &value) < 0) + continue; + /* skip any values that look like a path */ if (value[0] == '/') continue; /* skip nonprintable attributes */ len = strlen(value); - while (len > 0 && isprint(value[len-1])) + while (len > 0 && isprint((unsigned char) value[len-1])) len--; if (len > 0) continue; - printf(" %s{%s}==\"%s\"\n", key, name, value); + if (!GREEDY_REALLOC(sysattrs, n_allocated, n_items + 1)) + return log_oom(); + + sysattrs[n_items] = (SysAttr) { + .name = name, + .value = value, + }; + n_items++; } - printf("\n"); + + typesafe_qsort(sysattrs, n_items, sysattr_compare); + + for (size_t i = 0; i < n_items; i++) + printf(" %s{%s}==\"%s\"\n", is_parent ? "ATTRS" : "ATTR", sysattrs[i].name, sysattrs[i].value); + + puts(""); + + return 0; } static int print_device_chain(sd_device *device) { sd_device *child, *parent; - const char *str; + int r; printf("\n" "Udevadm info starts with the device specified by the devpath and then\n" @@ -95,30 +137,14 @@ static int print_device_chain(sd_device *device) { "and the attributes from one single parent device.\n" "\n"); - (void) sd_device_get_devpath(device, &str); - printf(" looking at device '%s':\n", str); - (void) sd_device_get_sysname(device, &str); - printf(" KERNEL==\"%s\"\n", str); - if (sd_device_get_subsystem(device, &str) < 0) - str = ""; - printf(" SUBSYSTEM==\"%s\"\n", str); - if (sd_device_get_driver(device, &str) < 0) - str = ""; - printf(" DRIVER==\"%s\"\n", str); - print_all_attributes(device, "ATTR"); + r = print_all_attributes(device, false); + if (r < 0) + return r; for (child = device; sd_device_get_parent(child, &parent) >= 0; child = parent) { - (void) sd_device_get_devpath(parent, &str); - printf(" looking at parent device '%s':\n", str); - (void) sd_device_get_sysname(parent, &str); - printf(" KERNELS==\"%s\"\n", str); - if (sd_device_get_subsystem(parent, &str) < 0) - str = ""; - printf(" SUBSYSTEMS==\"%s\"\n", str); - if (sd_device_get_driver(parent, &str) < 0) - str = ""; - printf(" DRIVERS==\"%s\"\n", str); - print_all_attributes(parent, "ATTRS"); + r = print_all_attributes(parent, true); + if (r < 0) + return r; } return 0; @@ -131,19 +157,23 @@ static int print_record(sd_device *device) { (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; } @@ -172,18 +202,18 @@ static int export_devices(void) { r = sd_device_enumerator_new(&e); if (r < 0) - return r; + return log_oom(); r = sd_device_enumerator_allow_uninitialized(e); if (r < 0) - return r; + return log_error_errno(r, "Failed to set allowing uninitialized flag: %m"); r = device_enumerator_scan_devices(e); if (r < 0) - return r; + return log_error_errno(r, "Failed to scan devices: %m"); FOREACH_DEVICE_AND_SUBSYSTEM(e, d) - print_record(d); + (void) print_record(d); return 0; } @@ -255,28 +285,22 @@ static int query_device(QueryType query, sd_device* device) { if (r < 0) return log_error_errno(r, "No device node found: %m"); - if (arg_root) - printf("%s\n", node); - else - printf("%s\n", node + STRLEN("/dev/")); + if (!arg_root) + assert_se(node = path_startswith(node, "/dev/")); + printf("%s\n", node); return 0; } case QUERY_SYMLINK: { - const char *devlink; - bool first = true; + const char *devlink, *prefix = ""; FOREACH_DEVICE_DEVLINK(device, devlink) { - if (!first) - printf(" "); - if (arg_root) - printf("%s", devlink); - else - printf("%s", devlink + STRLEN("/dev/")); - - first = false; + if (!arg_root) + assert_se(devlink = path_startswith(devlink, "/dev/")); + printf("%s%s", prefix, devlink); + prefix = " "; } - printf("\n"); + puts(""); return 0; } @@ -331,57 +355,55 @@ static int help(void) { " -P --export-prefix Export the key name with a prefix\n" " -e --export-db Export the content of the udev database\n" " -c --cleanup-db Clean up the udev database\n" + " -w --wait-for-initialization[=SECONDS]\n" + " Wait for device to be initialized\n" , program_invocation_short_name); return 0; } int info_main(int argc, char *argv[], void *userdata) { - _cleanup_(sd_device_unrefp) sd_device *device = NULL; + _cleanup_strv_free_ char **devices = NULL; _cleanup_free_ char *name = NULL; int c, r; static const struct option options[] = { - { "name", required_argument, NULL, 'n' }, - { "path", required_argument, NULL, 'p' }, - { "query", required_argument, NULL, 'q' }, - { "attribute-walk", no_argument, NULL, 'a' }, - { "cleanup-db", no_argument, NULL, 'c' }, - { "export-db", no_argument, NULL, 'e' }, - { "root", no_argument, NULL, 'r' }, - { "device-id-of-file", required_argument, NULL, 'd' }, - { "export", no_argument, NULL, 'x' }, - { "export-prefix", required_argument, NULL, 'P' }, - { "version", no_argument, NULL, 'V' }, - { "help", no_argument, NULL, 'h' }, + { "name", required_argument, NULL, 'n' }, + { "path", required_argument, NULL, 'p' }, + { "query", required_argument, NULL, 'q' }, + { "attribute-walk", no_argument, NULL, 'a' }, + { "cleanup-db", no_argument, NULL, 'c' }, + { "export-db", no_argument, NULL, 'e' }, + { "root", no_argument, NULL, 'r' }, + { "device-id-of-file", required_argument, NULL, 'd' }, + { "export", no_argument, NULL, 'x' }, + { "export-prefix", required_argument, NULL, 'P' }, + { "wait-for-initialization", optional_argument, NULL, 'w' }, + { "version", no_argument, NULL, 'V' }, + { "help", no_argument, NULL, 'h' }, {} }; ActionType action = ACTION_QUERY; QueryType query = QUERY_ALL; - while ((c = getopt_long(argc, argv, "aced:n:p:q:rxP:RVh", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "aced:n:p:q:rxP:w::Vh", 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")) @@ -394,10 +416,8 @@ int info_main(int argc, char *argv[], void *userdata) { query = QUERY_PATH; else if (streq(optarg, "all")) query = QUERY_ALL; - else { - log_error("unknown query type"); - return -EINVAL; - } + else + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "unknown query type"); break; case 'r': arg_root = true; @@ -420,8 +440,17 @@ int info_main(int argc, char *argv[], void *userdata) { arg_export = true; break; case 'P': + arg_export = true; arg_export_prefix = optarg; break; + case 'w': + if (optarg) { + r = parse_sec(optarg, &arg_wait_for_initialization_timeout); + if (r < 0) + return log_error_errno(r, "Failed to parse timeout value: %m"); + } else + arg_wait_for_initialization_timeout = USEC_INFINITY; + break; case 'V': return print_version(); case 'h': @@ -432,35 +461,55 @@ int info_main(int argc, char *argv[], void *userdata) { assert_not_reached("Unknown option"); } - if (IN_SET(action, ACTION_QUERY, ACTION_ATTRIBUTE_WALK) && - !device) { - /* A device argument is required. It may be an option or a positional arg. */ - - if (!argv[optind]) + if (action == ACTION_DEVICE_ID_FILE) { + if (argv[optind]) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "A device name or path is required"); + "Positional arguments are not allowed with -d/--device-id-of-file."); + assert(name); + return stat_device(name, arg_export, arg_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"); - r = find_device(argv[optind], NULL, &device); + 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\", an absolute path in /dev/ or /sys expected: %m", - argv[optind]); + 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", argv[optind]); - } + return log_error_errno(r, "Unknown device \"%s\": %m", *p); + + if (arg_wait_for_initialization_timeout > 0) { + sd_device *d; - switch (action) { - case ACTION_QUERY: - assert(device); - return query_device(query, device); + r = device_wait_for_initialization(device, NULL, arg_wait_for_initialization_timeout, &d); + if (r < 0) + return r; - case ACTION_ATTRIBUTE_WALK: - assert(device); - return print_device_chain(device); + sd_device_unref(device); + device = d; + } - case ACTION_DEVICE_ID_FILE: - assert(name); - return stat_device(name, arg_export, arg_export_prefix); + 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; } - assert_not_reached("Unknown action"); + return 0; }