2 * Copyright (C) 2004-2009 Kay Sievers <kay.sievers@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>
34 static bool skip_attribute(const char *name)
36 static const char const *skip[] = {
47 for (i = 0; i < ARRAY_SIZE(skip); i++)
48 if (strcmp(name, skip[i]) == 0)
53 static void print_all_attributes(struct udev_device *device, const char *key)
55 struct udev *udev = udev_device_get_udev(device);
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)
138 struct udev_list_entry *list_entry;
140 printf("P: %s\n", udev_device_get_devpath(device));
142 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
143 str = udev_device_get_devnode(device);
145 printf("N: %s\n", &str[len+1]);
147 i = udev_device_get_devlink_priority(device);
149 printf("L: %i\n", i);
151 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
152 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
153 printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
156 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
158 udev_list_entry_get_name(list_entry),
159 udev_list_entry_get_value(list_entry));
163 static int stat_device(const char *name, bool export, const char *prefix)
167 if (stat(name, &statbuf) != 0)
173 printf("%sMAJOR=%d\n"
175 prefix, major(statbuf.st_dev),
176 prefix, minor(statbuf.st_dev));
178 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
182 static int export_devices(struct udev *udev)
184 struct udev_enumerate *udev_enumerate;
185 struct udev_list_entry *list_entry;
187 udev_enumerate = udev_enumerate_new(udev);
188 if (udev_enumerate == NULL)
190 udev_enumerate_scan_devices(udev_enumerate);
191 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
192 struct udev_device *device;
194 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
195 if (device != NULL) {
196 print_record(device);
197 udev_device_unref(device);
200 udev_enumerate_unref(udev_enumerate);
204 static void cleanup_dir(DIR *dir, mode_t mask, int depth)
211 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
214 if (dent->d_name[0] == '.')
216 if (fstatat(dirfd(dir), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) != 0)
218 if ((stats.st_mode & mask) != 0)
220 if (S_ISDIR(stats.st_mode)) {
223 dir2 = fdopendir(openat(dirfd(dir), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
225 cleanup_dir(dir2, mask, depth-1);
228 unlinkat(dirfd(dir), dent->d_name, AT_REMOVEDIR);
230 unlinkat(dirfd(dir), dent->d_name, 0);
235 static void cleanup_db(struct udev *udev)
237 char filename[UTIL_PATH_SIZE];
240 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/queue.bin", NULL);
243 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/data", NULL);
244 dir = opendir(filename);
246 cleanup_dir(dir, S_ISVTX, 1);
250 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/links", NULL);
251 dir = opendir(filename);
253 cleanup_dir(dir, 0, 2);
257 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/tags", NULL);
258 dir = opendir(filename);
260 cleanup_dir(dir, 0, 2);
264 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/watch", NULL);
265 dir = opendir(filename);
267 cleanup_dir(dir, 0, 1);
271 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/firmware-missing", NULL);
272 dir = opendir(filename);
274 cleanup_dir(dir, 0, 1);
279 static int uinfo(struct udev *udev, int argc, char *argv[])
281 struct udev_device *device = NULL;
284 const char *export_prefix = NULL;
285 char path[UTIL_PATH_SIZE];
286 char name[UTIL_PATH_SIZE];
287 struct udev_list_entry *list_entry;
290 static const struct option options[] = {
291 { "name", required_argument, NULL, 'n' },
292 { "path", required_argument, NULL, 'p' },
293 { "query", required_argument, NULL, 'q' },
294 { "attribute-walk", no_argument, NULL, 'a' },
295 { "cleanup-db", no_argument, NULL, 'c' },
296 { "export-db", no_argument, NULL, 'e' },
297 { "root", no_argument, NULL, 'r' },
298 { "run", no_argument, NULL, 'R' },
299 { "device-id-of-file", required_argument, NULL, 'd' },
300 { "export", no_argument, NULL, 'x' },
301 { "export-prefix", required_argument, NULL, 'P' },
302 { "version", no_argument, NULL, 'V' },
303 { "help", no_argument, NULL, 'h' },
310 ACTION_ATTRIBUTE_WALK,
312 ACTION_DEVICE_ID_FILE,
313 } action = ACTION_NONE;
322 } query = QUERY_NONE;
328 option = getopt_long(argc, argv, "aced:n:p:q:rxP:RVh", options, NULL);
334 if (device != NULL) {
335 fprintf(stderr, "device already specified\n");
339 /* remove /dev if given */
340 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0)
341 util_strscpyl(name, sizeof(name), udev_get_dev_path(udev), "/", optarg, NULL);
343 util_strscpy(name, sizeof(name), optarg);
344 util_remove_trailing_chars(name, '/');
345 if (stat(name, &statbuf) < 0) {
346 fprintf(stderr, "device node not found\n");
352 if (S_ISBLK(statbuf.st_mode)) {
354 } else if (S_ISCHR(statbuf.st_mode)) {
357 fprintf(stderr, "device node has wrong file type\n");
361 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
362 if (device == NULL) {
363 fprintf(stderr, "device node not found\n");
370 if (device != NULL) {
371 fprintf(stderr, "device already specified\n");
375 /* add sys dir if needed */
376 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
377 util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), optarg, NULL);
379 util_strscpy(path, sizeof(path), optarg);
380 util_remove_trailing_chars(path, '/');
381 device = udev_device_new_from_syspath(udev, path);
382 if (device == NULL) {
383 fprintf(stderr, "device path not found\n");
389 action = ACTION_QUERY;
390 if (strcmp(optarg, "property") == 0 || strcmp(optarg, "env") == 0) {
391 query = QUERY_PROPERTY;
392 } else if (strcmp(optarg, "name") == 0) {
394 } else if (strcmp(optarg, "symlink") == 0) {
395 query = QUERY_SYMLINK;
396 } else if (strcmp(optarg, "path") == 0) {
398 } else if (strcmp(optarg, "all") == 0) {
401 fprintf(stderr, "unknown query type\n");
407 if (action == ACTION_NONE)
408 action = ACTION_ROOT;
412 printf("%s\n", udev_get_run_path(udev));
415 action = ACTION_DEVICE_ID_FILE;
416 util_strscpy(name, sizeof(name), optarg);
419 action = ACTION_ATTRIBUTE_WALK;
422 export_devices(udev);
431 export_prefix = optarg;
434 printf("%s\n", VERSION);
437 printf("Usage: udevadm info OPTIONS\n"
438 " --query=<type> query device information:\n"
439 " name name of device node\n"
440 " symlink pointing to node\n"
441 " path sys device path\n"
442 " property the device properties\n"
444 " --path=<syspath> sys device path used for query or attribute walk\n"
445 " --name=<name> node or symlink name used for query or attribute walk\n"
446 " --root prepend dev directory to path names\n"
447 " --attribute-walk print all key matches while walking along the chain\n"
448 " of parent devices\n"
449 " --device-id-of-file=<file> print major:minor of device containing this file\n"
450 " --export export key/value pairs\n"
451 " --export-prefix export the key name with a prefix\n"
452 " --export-db export the content of the udev database\n"
453 " --cleanup-db cleanup the udev database\n"
464 if (device == NULL) {
465 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
472 const char *node = udev_device_get_devnode(device);
475 fprintf(stderr, "no device node found\n");
481 printf("%s\n", udev_device_get_devnode(device));
483 size_t len = strlen(udev_get_dev_path(udev));
485 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
490 list_entry = udev_device_get_devlinks_list_entry(device);
491 while (list_entry != NULL) {
493 printf("%s", udev_list_entry_get_name(list_entry));
497 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
498 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
500 list_entry = udev_list_entry_get_next(list_entry);
501 if (list_entry != NULL)
507 printf("%s\n", udev_device_get_devpath(device));
510 list_entry = udev_device_get_properties_list_entry(device);
511 while (list_entry != NULL) {
513 const char *prefix = export_prefix;
517 printf("%s%s='%s'\n", prefix,
518 udev_list_entry_get_name(list_entry),
519 udev_list_entry_get_value(list_entry));
521 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
523 list_entry = udev_list_entry_get_next(list_entry);
527 print_record(device);
530 fprintf(stderr, "unknown query type\n");
534 case ACTION_ATTRIBUTE_WALK:
535 if (device == NULL) {
536 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
540 print_device_chain(device);
542 case ACTION_DEVICE_ID_FILE:
543 if (stat_device(name, export, export_prefix) != 0)
547 printf("%s\n", udev_get_dev_path(udev));
550 fprintf(stderr, "missing option\n");
556 udev_device_unref(device);
560 const struct udevadm_cmd udevadm_info = {
563 .help = "query sysfs or the udev database",