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"
34 #include "udevadm-util.h"
36 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) {
55 struct udev_list_entry *sysattr;
57 udev_list_entry_foreach(sysattr, udev_device_get_sysattr_list_entry(device)) {
62 name = udev_list_entry_get_name(sysattr);
63 if (skip_attribute(name))
66 value = udev_device_get_sysattr_value(device, name);
70 /* skip any values that look like a path */
74 /* skip nonprintable attributes */
76 while (len > 0 && isprint(value[len-1]))
81 printf(" %s{%s}==\"%s\"\n", key, name, value);
86 static int print_device_chain(struct udev_device *device) {
87 struct udev_device *device_parent;
91 "Udevadm info starts with the device specified by the devpath and then\n"
92 "walks up the chain of parent devices. It prints for every device\n"
93 "found, all possible attributes in the udev rules key format.\n"
94 "A rule to match, can be composed by the attributes of the device\n"
95 "and the attributes from one single parent device.\n"
98 printf(" looking at device '%s':\n", udev_device_get_devpath(device));
99 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device));
100 str = udev_device_get_subsystem(device);
103 printf(" SUBSYSTEM==\"%s\"\n", str);
104 str = udev_device_get_driver(device);
107 printf(" DRIVER==\"%s\"\n", str);
108 print_all_attributes(device, "ATTR");
110 device_parent = device;
112 device_parent = udev_device_get_parent(device_parent);
113 if (device_parent == NULL)
115 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent));
116 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent));
117 str = udev_device_get_subsystem(device_parent);
120 printf(" SUBSYSTEMS==\"%s\"\n", str);
121 str = udev_device_get_driver(device_parent);
124 printf(" DRIVERS==\"%s\"\n", str);
125 print_all_attributes(device_parent, "ATTRS");
126 } while (device_parent != NULL);
131 static void print_record(struct udev_device *device) {
134 struct udev_list_entry *list_entry;
136 printf("P: %s\n", udev_device_get_devpath(device));
138 str = udev_device_get_devnode(device);
140 printf("N: %s\n", str + strlen("/dev/"));
142 i = udev_device_get_devlink_priority(device);
144 printf("L: %i\n", i);
146 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device))
147 printf("S: %s\n", udev_list_entry_get_name(list_entry) + strlen("/dev/"));
149 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
151 udev_list_entry_get_name(list_entry),
152 udev_list_entry_get_value(list_entry));
156 static int stat_device(const char *name, bool export, const char *prefix) {
159 if (stat(name, &statbuf) != 0)
165 printf("%sMAJOR=%d\n"
167 prefix, major(statbuf.st_dev),
168 prefix, minor(statbuf.st_dev));
170 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
174 static int export_devices(struct udev *udev) {
175 struct udev_enumerate *udev_enumerate;
176 struct udev_list_entry *list_entry;
178 udev_enumerate = udev_enumerate_new(udev);
179 if (udev_enumerate == NULL)
181 udev_enumerate_scan_devices(udev_enumerate);
182 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
183 struct udev_device *device;
185 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
186 if (device != NULL) {
187 print_record(device);
188 udev_device_unref(device);
191 udev_enumerate_unref(udev_enumerate);
195 static void cleanup_dir(DIR *dir, mode_t mask, int depth) {
201 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
204 if (dent->d_name[0] == '.')
206 if (fstatat(dirfd(dir), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) != 0)
208 if ((stats.st_mode & mask) != 0)
210 if (S_ISDIR(stats.st_mode)) {
213 dir2 = fdopendir(openat(dirfd(dir), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
215 cleanup_dir(dir2, mask, depth-1);
218 unlinkat(dirfd(dir), dent->d_name, AT_REMOVEDIR);
220 unlinkat(dirfd(dir), dent->d_name, 0);
225 static void cleanup_db(struct udev *udev) {
228 unlink("/run/udev/queue.bin");
230 dir = opendir("/run/udev/data");
232 cleanup_dir(dir, S_ISVTX, 1);
236 dir = opendir("/run/udev/links");
238 cleanup_dir(dir, 0, 2);
242 dir = opendir("/run/udev/tags");
244 cleanup_dir(dir, 0, 2);
248 dir = opendir("/run/udev/static_node-tags");
250 cleanup_dir(dir, 0, 2);
254 dir = opendir("/run/udev/watch");
256 cleanup_dir(dir, 0, 1);
261 static int uinfo(struct udev *udev, int argc, char *argv[]) {
262 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
265 const char *export_prefix = NULL;
266 char name[UTIL_PATH_SIZE];
267 struct udev_list_entry *list_entry;
270 static const struct option options[] = {
271 { "name", required_argument, NULL, 'n' },
272 { "path", required_argument, NULL, 'p' },
273 { "query", required_argument, NULL, 'q' },
274 { "attribute-walk", no_argument, NULL, 'a' },
275 { "cleanup-db", no_argument, NULL, 'c' },
276 { "export-db", no_argument, NULL, 'e' },
277 { "root", no_argument, NULL, 'r' },
278 { "device-id-of-file", required_argument, NULL, 'd' },
279 { "export", no_argument, NULL, 'x' },
280 { "export-prefix", required_argument, NULL, 'P' },
281 { "version", no_argument, NULL, 'V' },
282 { "help", no_argument, NULL, 'h' },
286 static const char *usage =
287 "Usage: udevadm info [OPTIONS] [DEVPATH|FILE]\n"
288 " -q,--query=TYPE query device information:\n"
289 " name name of device node\n"
290 " symlink pointing to node\n"
291 " path sys device path\n"
292 " property the device properties\n"
294 " -p,--path=SYSPATH sys device path used for query or attribute walk\n"
295 " -n,--name=NAME node or symlink name used for query or attribute walk\n"
296 " -r,--root prepend dev directory to path names\n"
297 " -a,--attribute-walk print all key matches walking along the chain\n"
298 " of parent devices\n"
299 " -d,--device-id-of-file=FILE print major:minor of device containing this file\n"
300 " -x,--export export key/value pairs\n"
301 " -P,--export-prefix export the key name with a prefix\n"
302 " -e,--export-db export the content of the udev database\n"
303 " -c,--cleanup-db cleanup the udev database\n"
304 " --version print version of the program\n"
305 " -h,--help print this message\n";
309 ACTION_ATTRIBUTE_WALK,
310 ACTION_DEVICE_ID_FILE,
311 } action = ACTION_QUERY;
321 while ((c = getopt_long(argc, argv, "aced:n:p:q:rxP:RVh", options, NULL)) >= 0)
324 if (device != NULL) {
325 fprintf(stderr, "device already specified\n");
329 device = find_device(udev, optarg, "/dev/");
330 if (device == NULL) {
331 fprintf(stderr, "device node not found\n");
337 if (device != NULL) {
338 fprintf(stderr, "device already specified\n");
342 device = find_device(udev, optarg, "/sys");
343 if (device == NULL) {
344 fprintf(stderr, "syspath not found\n");
349 action = ACTION_QUERY;
350 if (streq(optarg, "property") || streq(optarg, "env"))
351 query = QUERY_PROPERTY;
352 else if (streq(optarg, "name"))
354 else if (streq(optarg, "symlink"))
355 query = QUERY_SYMLINK;
356 else if (streq(optarg, "path"))
358 else if (streq(optarg, "all"))
361 fprintf(stderr, "unknown query type\n");
369 action = ACTION_DEVICE_ID_FILE;
370 strscpy(name, sizeof(name), optarg);
373 action = ACTION_ATTRIBUTE_WALK;
376 export_devices(udev);
385 export_prefix = optarg;
388 printf("%s\n", VERSION);
391 printf("%s\n", usage);
401 fprintf(stderr, "%s\n", usage);
404 device = find_device(udev, argv[optind], NULL);
406 fprintf(stderr, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n");
413 const char *node = udev_device_get_devnode(device);
416 fprintf(stderr, "no device node found\n");
421 printf("%s\n", udev_device_get_devnode(device));
423 printf("%s\n", udev_device_get_devnode(device) + strlen("/dev/"));
427 list_entry = udev_device_get_devlinks_list_entry(device);
428 while (list_entry != NULL) {
430 printf("%s", udev_list_entry_get_name(list_entry));
432 printf("%s", udev_list_entry_get_name(list_entry) + strlen("/dev/"));
433 list_entry = udev_list_entry_get_next(list_entry);
434 if (list_entry != NULL)
440 printf("%s\n", udev_device_get_devpath(device));
443 list_entry = udev_device_get_properties_list_entry(device);
444 while (list_entry != NULL) {
446 const char *prefix = export_prefix;
450 printf("%s%s='%s'\n", prefix,
451 udev_list_entry_get_name(list_entry),
452 udev_list_entry_get_value(list_entry));
454 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
456 list_entry = udev_list_entry_get_next(list_entry);
460 print_record(device);
463 assert_not_reached("unknown query type");
466 case ACTION_ATTRIBUTE_WALK:
467 if (!device && argv[optind]) {
468 device = find_device(udev, argv[optind], NULL);
470 fprintf(stderr, "Unknown device, absolute path in /dev/ or /sys expected.\n");
475 fprintf(stderr, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n");
478 print_device_chain(device);
480 case ACTION_DEVICE_ID_FILE:
481 if (stat_device(name, export, export_prefix) != 0)
489 const struct udevadm_cmd udevadm_info = {
492 .help = "query sysfs or the udev database",