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)
37 static const char* const skip[] = {
48 for (i = 0; i < ELEMENTSOF(skip); i++)
49 if (streq(name, skip[i]))
54 static void print_all_attributes(struct udev_device *device, const char *key)
56 struct udev_list_entry *sysattr;
58 udev_list_entry_foreach(sysattr, udev_device_get_sysattr_list_entry(device)) {
63 name = udev_list_entry_get_name(sysattr);
64 if (skip_attribute(name))
67 value = udev_device_get_sysattr_value(device, name);
71 /* skip any values that look like a path */
75 /* skip nonprintable attributes */
77 while (len > 0 && isprint(value[len-1]))
82 printf(" %s{%s}==\"%s\"\n", key, name, value);
87 static int print_device_chain(struct udev_device *device)
89 struct udev_device *device_parent;
93 "Udevadm info starts with the device specified by the devpath and then\n"
94 "walks up the chain of parent devices. It prints for every device\n"
95 "found, all possible attributes in the udev rules key format.\n"
96 "A rule to match, can be composed by the attributes of the device\n"
97 "and the attributes from one single parent device.\n"
100 printf(" looking at device '%s':\n", udev_device_get_devpath(device));
101 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device));
102 str = udev_device_get_subsystem(device);
105 printf(" SUBSYSTEM==\"%s\"\n", str);
106 str = udev_device_get_driver(device);
109 printf(" DRIVER==\"%s\"\n", str);
110 print_all_attributes(device, "ATTR");
112 device_parent = device;
114 device_parent = udev_device_get_parent(device_parent);
115 if (device_parent == NULL)
117 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent));
118 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent));
119 str = udev_device_get_subsystem(device_parent);
122 printf(" SUBSYSTEMS==\"%s\"\n", str);
123 str = udev_device_get_driver(device_parent);
126 printf(" DRIVERS==\"%s\"\n", str);
127 print_all_attributes(device_parent, "ATTRS");
128 } while (device_parent != NULL);
133 static void print_record(struct udev_device *device)
137 struct udev_list_entry *list_entry;
139 printf("P: %s\n", udev_device_get_devpath(device));
141 str = udev_device_get_devnode(device);
143 printf("N: %s\n", str + strlen("/dev/"));
145 i = udev_device_get_devlink_priority(device);
147 printf("L: %i\n", i);
149 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device))
150 printf("S: %s\n", udev_list_entry_get_name(list_entry) + strlen("/dev/"));
152 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
154 udev_list_entry_get_name(list_entry),
155 udev_list_entry_get_value(list_entry));
159 static int stat_device(const char *name, bool export, const char *prefix)
163 if (stat(name, &statbuf) != 0)
169 printf("%sMAJOR=%d\n"
171 prefix, major(statbuf.st_dev),
172 prefix, minor(statbuf.st_dev));
174 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
178 static int export_devices(struct udev *udev)
180 struct udev_enumerate *udev_enumerate;
181 struct udev_list_entry *list_entry;
183 udev_enumerate = udev_enumerate_new(udev);
184 if (udev_enumerate == NULL)
186 udev_enumerate_scan_devices(udev_enumerate);
187 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
188 struct udev_device *device;
190 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
191 if (device != NULL) {
192 print_record(device);
193 udev_device_unref(device);
196 udev_enumerate_unref(udev_enumerate);
200 static void cleanup_dir(DIR *dir, mode_t mask, int depth)
207 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
210 if (dent->d_name[0] == '.')
212 if (fstatat(dirfd(dir), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) != 0)
214 if ((stats.st_mode & mask) != 0)
216 if (S_ISDIR(stats.st_mode)) {
219 dir2 = fdopendir(openat(dirfd(dir), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
221 cleanup_dir(dir2, mask, depth-1);
224 unlinkat(dirfd(dir), dent->d_name, AT_REMOVEDIR);
226 unlinkat(dirfd(dir), dent->d_name, 0);
231 static void cleanup_db(struct udev *udev)
235 unlink("/run/udev/queue.bin");
237 dir = opendir("/run/udev/data");
239 cleanup_dir(dir, S_ISVTX, 1);
243 dir = opendir("/run/udev/links");
245 cleanup_dir(dir, 0, 2);
249 dir = opendir("/run/udev/tags");
251 cleanup_dir(dir, 0, 2);
255 dir = opendir("/run/udev/static_node-tags");
257 cleanup_dir(dir, 0, 2);
261 dir = opendir("/run/udev/watch");
263 cleanup_dir(dir, 0, 1);
268 static struct udev_device *find_device(struct udev *udev, const char *id, const char *prefix)
270 char name[UTIL_PATH_SIZE];
272 if (prefix && !startswith(id, prefix)) {
273 strscpyl(name, sizeof(name), prefix, id, NULL);
277 if (startswith(id, "/dev/")) {
281 if (stat(id, &statbuf) < 0)
284 if (S_ISBLK(statbuf.st_mode))
286 else if (S_ISCHR(statbuf.st_mode))
291 return udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
292 } else if (startswith(id, "/sys/"))
293 return udev_device_new_from_syspath(udev, id);
298 static int uinfo(struct udev *udev, int argc, char *argv[])
300 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
303 const char *export_prefix = NULL;
304 char name[UTIL_PATH_SIZE];
305 struct udev_list_entry *list_entry;
308 static const struct option options[] = {
309 { "name", required_argument, NULL, 'n' },
310 { "path", required_argument, NULL, 'p' },
311 { "query", required_argument, NULL, 'q' },
312 { "attribute-walk", no_argument, NULL, 'a' },
313 { "cleanup-db", no_argument, NULL, 'c' },
314 { "export-db", no_argument, NULL, 'e' },
315 { "root", no_argument, NULL, 'r' },
316 { "device-id-of-file", required_argument, NULL, 'd' },
317 { "export", no_argument, NULL, 'x' },
318 { "export-prefix", required_argument, NULL, 'P' },
319 { "version", no_argument, NULL, 'V' },
320 { "help", no_argument, NULL, 'h' },
324 static const char *usage =
325 "Usage: udevadm info [OPTIONS] [DEVPATH|FILE]\n"
326 " -q,--query=TYPE query device information:\n"
327 " name name of device node\n"
328 " symlink pointing to node\n"
329 " path sys device path\n"
330 " property the device properties\n"
332 " -p,--path=SYSPATH sys device path used for query or attribute walk\n"
333 " -n,--name=NAME node or symlink name used for query or attribute walk\n"
334 " -r,--root prepend dev directory to path names\n"
335 " -a,--attribute-walk print all key matches walking along the chain\n"
336 " of parent devices\n"
337 " -d,--device-id-of-file=FILE print major:minor of device containing this file\n"
338 " -x,--export export key/value pairs\n"
339 " -P,--export-prefix export the key name with a prefix\n"
340 " -e,--export-db export the content of the udev database\n"
341 " -c,--cleanup-db cleanup the udev database\n"
342 " --version print version of the program\n"
343 " -h,--help print this message\n";
347 ACTION_ATTRIBUTE_WALK,
348 ACTION_DEVICE_ID_FILE,
349 } action = ACTION_QUERY;
359 while ((c = getopt_long(argc, argv, "aced:n:p:q:rxP:RVh", options, NULL)) >= 0)
362 if (device != NULL) {
363 fprintf(stderr, "device already specified\n");
367 device = find_device(udev, optarg, "/dev/");
368 if (device == NULL) {
369 fprintf(stderr, "device node not found\n");
375 if (device != NULL) {
376 fprintf(stderr, "device already specified\n");
380 device = find_device(udev, optarg, "/sys");
381 if (device == NULL) {
382 fprintf(stderr, "syspath not found\n");
387 action = ACTION_QUERY;
388 if (streq(optarg, "property") || streq(optarg, "env"))
389 query = QUERY_PROPERTY;
390 else if (streq(optarg, "name"))
392 else if (streq(optarg, "symlink"))
393 query = QUERY_SYMLINK;
394 else if (streq(optarg, "path"))
396 else if (streq(optarg, "all"))
399 fprintf(stderr, "unknown query type\n");
407 action = ACTION_DEVICE_ID_FILE;
408 strscpy(name, sizeof(name), optarg);
411 action = ACTION_ATTRIBUTE_WALK;
414 export_devices(udev);
423 export_prefix = optarg;
426 printf("%s\n", VERSION);
429 printf("%s\n", usage);
439 fprintf(stderr, "%s\n", usage);
442 device = find_device(udev, argv[optind], NULL);
444 fprintf(stderr, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n");
451 const char *node = udev_device_get_devnode(device);
454 fprintf(stderr, "no device node found\n");
459 printf("%s\n", udev_device_get_devnode(device));
461 printf("%s\n", udev_device_get_devnode(device) + strlen("/dev/"));
465 list_entry = udev_device_get_devlinks_list_entry(device);
466 while (list_entry != NULL) {
468 printf("%s", udev_list_entry_get_name(list_entry));
470 printf("%s", udev_list_entry_get_name(list_entry) + strlen("/dev/"));
471 list_entry = udev_list_entry_get_next(list_entry);
472 if (list_entry != NULL)
478 printf("%s\n", udev_device_get_devpath(device));
481 list_entry = udev_device_get_properties_list_entry(device);
482 while (list_entry != NULL) {
484 const char *prefix = export_prefix;
488 printf("%s%s='%s'\n", prefix,
489 udev_list_entry_get_name(list_entry),
490 udev_list_entry_get_value(list_entry));
492 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
494 list_entry = udev_list_entry_get_next(list_entry);
498 print_record(device);
501 assert_not_reached("unknown query type");
504 case ACTION_ATTRIBUTE_WALK:
505 if (!device && argv[optind]) {
506 device = find_device(udev, argv[optind], NULL);
508 fprintf(stderr, "Unknown device, absolute path in /dev/ or /sys expected.\n");
513 fprintf(stderr, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n");
516 print_device_chain(device);
518 case ACTION_DEVICE_ID_FILE:
519 if (stat_device(name, export, export_prefix) != 0)
527 const struct udevadm_cmd udevadm_info = {
530 .help = "query sysfs or the udev database",