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_list_entry *sysattr;
57 udev_list_entry_foreach(sysattr, udev_device_get_sysattr_list_entry(device)) {
58 struct udev *udev = udev_device_get_udev(device);
63 name = udev_list_entry_get_name(sysattr);
64 if (skip_attribute(name))
67 value = udev_device_get_sysattr_value(device, name);
70 dbg(udev, "attr '%s'='%s'\n", name, value);
72 /* skip nonprintable attributes */
74 while (len > 0 && isprint(value[len-1]))
77 dbg(udev, "attribute value of '%s' non-printable, skip\n", name);
81 printf(" %s{%s}==\"%s\"\n", key, name, value);
86 static int print_device_chain(struct udev_device *device)
88 struct udev_device *device_parent;
92 "Udevadm info starts with the device specified by the devpath and then\n"
93 "walks up the chain of parent devices. It prints for every device\n"
94 "found, all possible attributes in the udev rules key format.\n"
95 "A rule to match, can be composed by the attributes of the device\n"
96 "and the attributes from one single parent device.\n"
99 printf(" looking at device '%s':\n", udev_device_get_devpath(device));
100 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device));
101 str = udev_device_get_subsystem(device);
104 printf(" SUBSYSTEM==\"%s\"\n", str);
105 str = udev_device_get_driver(device);
108 printf(" DRIVER==\"%s\"\n", str);
109 print_all_attributes(device, "ATTR");
111 device_parent = device;
113 device_parent = udev_device_get_parent(device_parent);
114 if (device_parent == NULL)
116 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent));
117 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent));
118 str = udev_device_get_subsystem(device_parent);
121 printf(" SUBSYSTEMS==\"%s\"\n", str);
122 str = udev_device_get_driver(device_parent);
125 printf(" DRIVERS==\"%s\"\n", str);
126 print_all_attributes(device_parent, "ATTRS");
127 } while (device_parent != NULL);
132 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 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
142 str = udev_device_get_devnode(device);
144 printf("N: %s\n", &str[len+1]);
146 i = udev_device_get_devlink_priority(device);
148 printf("L: %i\n", i);
150 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
151 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
152 printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
155 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
157 udev_list_entry_get_name(list_entry),
158 udev_list_entry_get_value(list_entry));
162 static int stat_device(const char *name, bool export, const char *prefix)
166 if (stat(name, &statbuf) != 0)
172 printf("%sMAJOR=%d\n"
174 prefix, major(statbuf.st_dev),
175 prefix, minor(statbuf.st_dev));
177 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
181 static int export_devices(struct udev *udev)
183 struct udev_enumerate *udev_enumerate;
184 struct udev_list_entry *list_entry;
186 udev_enumerate = udev_enumerate_new(udev);
187 if (udev_enumerate == NULL)
189 udev_enumerate_scan_devices(udev_enumerate);
190 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
191 struct udev_device *device;
193 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
194 if (device != NULL) {
195 print_record(device);
196 udev_device_unref(device);
199 udev_enumerate_unref(udev_enumerate);
203 static void cleanup_dir(DIR *dir, mode_t mask, int depth)
210 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
213 if (dent->d_name[0] == '.')
215 if (fstatat(dirfd(dir), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) != 0)
217 if ((stats.st_mode & mask) != 0)
219 if (S_ISDIR(stats.st_mode)) {
222 dir2 = fdopendir(openat(dirfd(dir), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
224 cleanup_dir(dir2, mask, depth-1);
227 unlinkat(dirfd(dir), dent->d_name, AT_REMOVEDIR);
229 unlinkat(dirfd(dir), dent->d_name, 0);
234 static void cleanup_db(struct udev *udev)
236 char filename[UTIL_PATH_SIZE];
239 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/queue.bin", NULL);
242 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/data", NULL);
243 dir = opendir(filename);
245 cleanup_dir(dir, S_ISVTX, 1);
249 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/links", NULL);
250 dir = opendir(filename);
252 cleanup_dir(dir, 0, 2);
256 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/tags", NULL);
257 dir = opendir(filename);
259 cleanup_dir(dir, 0, 2);
263 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/watch", NULL);
264 dir = opendir(filename);
266 cleanup_dir(dir, 0, 1);
270 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/firmware-missing", NULL);
271 dir = opendir(filename);
273 cleanup_dir(dir, 0, 1);
278 int udevadm_info(struct udev *udev, int argc, char *argv[])
280 struct udev_device *device = NULL;
283 const char *export_prefix = NULL;
284 char path[UTIL_PATH_SIZE];
285 char name[UTIL_PATH_SIZE];
286 struct udev_list_entry *list_entry;
289 static const struct option options[] = {
290 { "name", required_argument, NULL, 'n' },
291 { "path", required_argument, NULL, 'p' },
292 { "query", required_argument, NULL, 'q' },
293 { "attribute-walk", no_argument, NULL, 'a' },
294 { "cleanup-db", no_argument, NULL, 'c' },
295 { "export-db", no_argument, NULL, 'e' },
296 { "root", no_argument, NULL, 'r' },
297 { "run", no_argument, NULL, 'R' },
298 { "device-id-of-file", required_argument, NULL, 'd' },
299 { "export", no_argument, NULL, 'x' },
300 { "export-prefix", required_argument, NULL, 'P' },
301 { "version", no_argument, NULL, 'V' },
302 { "help", no_argument, NULL, 'h' },
309 ACTION_ATTRIBUTE_WALK,
311 ACTION_DEVICE_ID_FILE,
312 } action = ACTION_NONE;
321 } query = QUERY_NONE;
327 option = getopt_long(argc, argv, "aced:n:p:q:rxP:RVh", options, NULL);
331 dbg(udev, "option '%c'\n", option);
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"
463 if (device == NULL) {
464 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
471 const char *node = udev_device_get_devnode(device);
474 fprintf(stderr, "no device node found\n");
480 printf("%s\n", udev_device_get_devnode(device));
482 size_t len = strlen(udev_get_dev_path(udev));
484 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
489 list_entry = udev_device_get_devlinks_list_entry(device);
490 while (list_entry != NULL) {
492 printf("%s", udev_list_entry_get_name(list_entry));
496 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
497 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
499 list_entry = udev_list_entry_get_next(list_entry);
500 if (list_entry != NULL)
506 printf("%s\n", udev_device_get_devpath(device));
509 list_entry = udev_device_get_properties_list_entry(device);
510 while (list_entry != NULL) {
512 const char *prefix = export_prefix;
516 printf("%s%s='%s'\n", prefix,
517 udev_list_entry_get_name(list_entry),
518 udev_list_entry_get_value(list_entry));
520 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
522 list_entry = udev_list_entry_get_next(list_entry);
526 print_record(device);
529 fprintf(stderr, "unknown query type\n");
533 case ACTION_ATTRIBUTE_WALK:
534 if (device == NULL) {
535 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
539 print_device_chain(device);
541 case ACTION_DEVICE_ID_FILE:
542 if (stat_device(name, export, export_prefix) != 0)
546 printf("%s\n", udev_get_dev_path(udev));
549 fprintf(stderr, "missing option\n");
555 udev_device_unref(device);