2 * Copyright (C) 2004-2009 Kay Sievers <kay@vrfy.org>
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30 #include <sys/types.h>
33 #include "udev-util.h"
35 static bool skip_attribute(const char *name) {
36 static const char* const skip[] = {
47 for (i = 0; i < ELEMENTSOF(skip); i++)
48 if (streq(name, skip[i]))
53 static void print_all_attributes(struct udev_device *device, const char *key) {
54 struct udev_list_entry *sysattr;
56 udev_list_entry_foreach(sysattr, udev_device_get_sysattr_list_entry(device)) {
61 name = udev_list_entry_get_name(sysattr);
62 if (skip_attribute(name))
65 value = udev_device_get_sysattr_value(device, name);
69 /* skip any values that look like a path */
73 /* skip nonprintable attributes */
75 while (len > 0 && isprint(value[len-1]))
80 printf(" %s{%s}==\"%s\"\n", key, name, value);
85 static int print_device_chain(struct udev_device *device) {
86 struct udev_device *device_parent;
90 "Udevadm info starts with the device specified by the devpath and then\n"
91 "walks up the chain of parent devices. It prints for every device\n"
92 "found, all possible attributes in the udev rules key format.\n"
93 "A rule to match, can be composed by the attributes of the device\n"
94 "and the attributes from one single parent device.\n"
97 printf(" looking at device '%s':\n", udev_device_get_devpath(device));
98 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device));
99 str = udev_device_get_subsystem(device);
102 printf(" SUBSYSTEM==\"%s\"\n", str);
103 str = udev_device_get_driver(device);
106 printf(" DRIVER==\"%s\"\n", str);
107 print_all_attributes(device, "ATTR");
109 device_parent = device;
111 device_parent = udev_device_get_parent(device_parent);
112 if (device_parent == NULL)
114 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent));
115 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent));
116 str = udev_device_get_subsystem(device_parent);
119 printf(" SUBSYSTEMS==\"%s\"\n", str);
120 str = udev_device_get_driver(device_parent);
123 printf(" DRIVERS==\"%s\"\n", str);
124 print_all_attributes(device_parent, "ATTRS");
125 } while (device_parent != NULL);
130 static void print_record(struct udev_device *device) {
133 struct udev_list_entry *list_entry;
135 printf("P: %s\n", udev_device_get_devpath(device));
137 str = udev_device_get_devnode(device);
139 printf("N: %s\n", str + strlen("/dev/"));
141 i = udev_device_get_devlink_priority(device);
143 printf("L: %i\n", i);
145 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device))
146 printf("S: %s\n", udev_list_entry_get_name(list_entry) + strlen("/dev/"));
148 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
150 udev_list_entry_get_name(list_entry),
151 udev_list_entry_get_value(list_entry));
155 static int stat_device(const char *name, bool export, const char *prefix) {
158 if (stat(name, &statbuf) != 0)
164 printf("%sMAJOR=%d\n"
166 prefix, major(statbuf.st_dev),
167 prefix, minor(statbuf.st_dev));
169 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
173 static int export_devices(struct udev *udev) {
174 struct udev_enumerate *udev_enumerate;
175 struct udev_list_entry *list_entry;
177 udev_enumerate = udev_enumerate_new(udev);
178 if (udev_enumerate == NULL)
180 udev_enumerate_scan_devices(udev_enumerate);
181 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
182 struct udev_device *device;
184 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
185 if (device != NULL) {
186 print_record(device);
187 udev_device_unref(device);
190 udev_enumerate_unref(udev_enumerate);
194 static void cleanup_dir(DIR *dir, mode_t mask, int depth) {
200 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
203 if (dent->d_name[0] == '.')
205 if (fstatat(dirfd(dir), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) != 0)
207 if ((stats.st_mode & mask) != 0)
209 if (S_ISDIR(stats.st_mode)) {
212 dir2 = fdopendir(openat(dirfd(dir), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
214 cleanup_dir(dir2, mask, depth-1);
217 unlinkat(dirfd(dir), dent->d_name, AT_REMOVEDIR);
219 unlinkat(dirfd(dir), dent->d_name, 0);
224 static void cleanup_db(struct udev *udev) {
227 unlink("/run/udev/queue.bin");
229 dir = opendir("/run/udev/data");
231 cleanup_dir(dir, S_ISVTX, 1);
235 dir = opendir("/run/udev/links");
237 cleanup_dir(dir, 0, 2);
241 dir = opendir("/run/udev/tags");
243 cleanup_dir(dir, 0, 2);
247 dir = opendir("/run/udev/static_node-tags");
249 cleanup_dir(dir, 0, 2);
253 dir = opendir("/run/udev/watch");
255 cleanup_dir(dir, 0, 1);
260 static struct udev_device *find_device(struct udev *udev, const char *id, const char *prefix) {
261 char name[UTIL_PATH_SIZE];
263 if (prefix && !startswith(id, prefix)) {
264 strscpyl(name, sizeof(name), prefix, id, NULL);
268 if (startswith(id, "/dev/")) {
272 if (stat(id, &statbuf) < 0)
275 if (S_ISBLK(statbuf.st_mode))
277 else if (S_ISCHR(statbuf.st_mode))
282 return udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
283 } else if (startswith(id, "/sys/"))
284 return udev_device_new_from_syspath(udev, id);
289 static int uinfo(struct udev *udev, int argc, char *argv[]) {
290 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
293 const char *export_prefix = NULL;
294 char name[UTIL_PATH_SIZE];
295 struct udev_list_entry *list_entry;
298 static const struct option options[] = {
299 { "name", required_argument, NULL, 'n' },
300 { "path", required_argument, NULL, 'p' },
301 { "query", required_argument, NULL, 'q' },
302 { "attribute-walk", no_argument, NULL, 'a' },
303 { "cleanup-db", no_argument, NULL, 'c' },
304 { "export-db", no_argument, NULL, 'e' },
305 { "root", no_argument, NULL, 'r' },
306 { "device-id-of-file", required_argument, NULL, 'd' },
307 { "export", no_argument, NULL, 'x' },
308 { "export-prefix", required_argument, NULL, 'P' },
309 { "version", no_argument, NULL, 'V' },
310 { "help", no_argument, NULL, 'h' },
314 static const char *usage =
315 "Usage: udevadm info [OPTIONS] [DEVPATH|FILE]\n"
316 " -q,--query=TYPE query device information:\n"
317 " name name of device node\n"
318 " symlink pointing to node\n"
319 " path sys device path\n"
320 " property the device properties\n"
322 " -p,--path=SYSPATH sys device path used for query or attribute walk\n"
323 " -n,--name=NAME node or symlink name used for query or attribute walk\n"
324 " -r,--root prepend dev directory to path names\n"
325 " -a,--attribute-walk print all key matches walking along the chain\n"
326 " of parent devices\n"
327 " -d,--device-id-of-file=FILE print major:minor of device containing this file\n"
328 " -x,--export export key/value pairs\n"
329 " -P,--export-prefix export the key name with a prefix\n"
330 " -e,--export-db export the content of the udev database\n"
331 " -c,--cleanup-db cleanup the udev database\n"
332 " --version print version of the program\n"
333 " -h,--help print this message\n";
337 ACTION_ATTRIBUTE_WALK,
338 ACTION_DEVICE_ID_FILE,
339 } action = ACTION_QUERY;
349 while ((c = getopt_long(argc, argv, "aced:n:p:q:rxP:RVh", options, NULL)) >= 0)
352 if (device != NULL) {
353 fprintf(stderr, "device already specified\n");
357 device = find_device(udev, optarg, "/dev/");
358 if (device == NULL) {
359 fprintf(stderr, "device node not found\n");
365 if (device != NULL) {
366 fprintf(stderr, "device already specified\n");
370 device = find_device(udev, optarg, "/sys");
371 if (device == NULL) {
372 fprintf(stderr, "syspath not found\n");
377 action = ACTION_QUERY;
378 if (streq(optarg, "property") || streq(optarg, "env"))
379 query = QUERY_PROPERTY;
380 else if (streq(optarg, "name"))
382 else if (streq(optarg, "symlink"))
383 query = QUERY_SYMLINK;
384 else if (streq(optarg, "path"))
386 else if (streq(optarg, "all"))
389 fprintf(stderr, "unknown query type\n");
397 action = ACTION_DEVICE_ID_FILE;
398 strscpy(name, sizeof(name), optarg);
401 action = ACTION_ATTRIBUTE_WALK;
404 export_devices(udev);
413 export_prefix = optarg;
416 printf("%s\n", VERSION);
419 printf("%s\n", usage);
429 fprintf(stderr, "%s\n", usage);
432 device = find_device(udev, argv[optind], NULL);
434 fprintf(stderr, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n");
441 const char *node = udev_device_get_devnode(device);
444 fprintf(stderr, "no device node found\n");
449 printf("%s\n", udev_device_get_devnode(device));
451 printf("%s\n", udev_device_get_devnode(device) + strlen("/dev/"));
455 list_entry = udev_device_get_devlinks_list_entry(device);
456 while (list_entry != NULL) {
458 printf("%s", udev_list_entry_get_name(list_entry));
460 printf("%s", udev_list_entry_get_name(list_entry) + strlen("/dev/"));
461 list_entry = udev_list_entry_get_next(list_entry);
462 if (list_entry != NULL)
468 printf("%s\n", udev_device_get_devpath(device));
471 list_entry = udev_device_get_properties_list_entry(device);
472 while (list_entry != NULL) {
474 const char *prefix = export_prefix;
478 printf("%s%s='%s'\n", prefix,
479 udev_list_entry_get_name(list_entry),
480 udev_list_entry_get_value(list_entry));
482 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
484 list_entry = udev_list_entry_get_next(list_entry);
488 print_record(device);
491 assert_not_reached("unknown query type");
494 case ACTION_ATTRIBUTE_WALK:
495 if (!device && argv[optind]) {
496 device = find_device(udev, argv[optind], NULL);
498 fprintf(stderr, "Unknown device, absolute path in /dev/ or /sys expected.\n");
503 fprintf(stderr, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n");
506 print_device_chain(device);
508 case ACTION_DEVICE_ID_FILE:
509 if (stat_device(name, export, export_prefix) != 0)
517 const struct udevadm_cmd udevadm_info = {
520 .help = "query sysfs or the udev database",