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=%u\n"
167 prefix, major(statbuf.st_dev),
168 prefix, minor(statbuf.st_dev));
170 printf("%u:%u\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 void help(void) {
263 printf("%s info [OPTIONS] [DEVPATH|FILE]\n\n"
264 "Query sysfs or the udev database.\n\n"
265 " -h --help Print this message\n"
266 " --version Print version of the program\n"
267 " -q --query=TYPE Query device information:\n"
268 " name Name of device node\n"
269 " symlink Pointing to node\n"
270 " path sysfs device path\n"
271 " property The device properties\n"
273 " -p --path=SYSPATH sysfs device path used for query or attribute walk\n"
274 " -n --name=NAME Node or symlink name used for query or attribute walk\n"
275 " -r --root Prepend dev directory to path names\n"
276 " -a --attribute-walk Print all key matches walking along the chain\n"
277 " of parent devices\n"
278 " -d --device-id-of-file=FILE Print major:minor of device containing this file\n"
279 " -x --export Export key/value pairs\n"
280 " -P --export-prefix Export the key name with a prefix\n"
281 " -e --export-db Export the content of the udev database\n"
282 " -c --cleanup-db Clean up the udev database\n"
283 , program_invocation_short_name);
286 static int uinfo(struct udev *udev, int argc, char *argv[]) {
287 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
290 const char *export_prefix = NULL;
291 char name[UTIL_PATH_SIZE];
292 struct udev_list_entry *list_entry;
295 static const struct option options[] = {
296 { "name", required_argument, NULL, 'n' },
297 { "path", required_argument, NULL, 'p' },
298 { "query", required_argument, NULL, 'q' },
299 { "attribute-walk", no_argument, NULL, 'a' },
300 { "cleanup-db", no_argument, NULL, 'c' },
301 { "export-db", no_argument, NULL, 'e' },
302 { "root", no_argument, NULL, 'r' },
303 { "device-id-of-file", required_argument, NULL, 'd' },
304 { "export", no_argument, NULL, 'x' },
305 { "export-prefix", required_argument, NULL, 'P' },
306 { "version", no_argument, NULL, 'V' },
307 { "help", no_argument, NULL, 'h' },
313 ACTION_ATTRIBUTE_WALK,
314 ACTION_DEVICE_ID_FILE,
315 } action = ACTION_QUERY;
325 while ((c = getopt_long(argc, argv, "aced:n:p:q:rxP:RVh", options, NULL)) >= 0)
328 if (device != NULL) {
329 fprintf(stderr, "device already specified\n");
333 device = find_device(udev, optarg, "/dev/");
334 if (device == NULL) {
335 fprintf(stderr, "device node not found\n");
341 if (device != NULL) {
342 fprintf(stderr, "device already specified\n");
346 device = find_device(udev, optarg, "/sys");
347 if (device == NULL) {
348 fprintf(stderr, "syspath not found\n");
353 action = ACTION_QUERY;
354 if (streq(optarg, "property") || streq(optarg, "env"))
355 query = QUERY_PROPERTY;
356 else if (streq(optarg, "name"))
358 else if (streq(optarg, "symlink"))
359 query = QUERY_SYMLINK;
360 else if (streq(optarg, "path"))
362 else if (streq(optarg, "all"))
365 fprintf(stderr, "unknown query type\n");
373 action = ACTION_DEVICE_ID_FILE;
374 strscpy(name, sizeof(name), optarg);
377 action = ACTION_ATTRIBUTE_WALK;
380 export_devices(udev);
389 export_prefix = optarg;
392 printf("%s\n", VERSION);
408 device = find_device(udev, argv[optind], NULL);
410 fprintf(stderr, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n");
417 const char *node = udev_device_get_devnode(device);
420 fprintf(stderr, "no device node found\n");
425 printf("%s\n", udev_device_get_devnode(device));
427 printf("%s\n", udev_device_get_devnode(device) + strlen("/dev/"));
431 list_entry = udev_device_get_devlinks_list_entry(device);
432 while (list_entry != NULL) {
434 printf("%s", udev_list_entry_get_name(list_entry));
436 printf("%s", udev_list_entry_get_name(list_entry) + strlen("/dev/"));
437 list_entry = udev_list_entry_get_next(list_entry);
438 if (list_entry != NULL)
444 printf("%s\n", udev_device_get_devpath(device));
447 list_entry = udev_device_get_properties_list_entry(device);
448 while (list_entry != NULL) {
450 const char *prefix = export_prefix;
454 printf("%s%s='%s'\n", prefix,
455 udev_list_entry_get_name(list_entry),
456 udev_list_entry_get_value(list_entry));
458 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
460 list_entry = udev_list_entry_get_next(list_entry);
464 print_record(device);
467 assert_not_reached("unknown query type");
470 case ACTION_ATTRIBUTE_WALK:
471 if (!device && argv[optind]) {
472 device = find_device(udev, argv[optind], NULL);
474 fprintf(stderr, "Unknown device, absolute path in /dev/ or /sys expected.\n");
479 fprintf(stderr, "Unknown device, --name=, --path=, or absolute path in /dev/ or /sys expected.\n");
482 print_device_chain(device);
484 case ACTION_DEVICE_ID_FILE:
485 if (stat_device(name, export, export_prefix) != 0)
493 const struct udevadm_cmd udevadm_info = {
496 .help = "Query sysfs or the udev database",