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 void print_all_attributes(struct udev_device *device, const char *key)
36 struct udev *udev = udev_device_get_udev(device);
40 dir = opendir(udev_device_get_syspath(device));
42 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
47 if (dent->d_name[0] == '.')
50 if (strcmp(dent->d_name, "uevent") == 0)
52 if (strcmp(dent->d_name, "dev") == 0)
55 if (fstatat(dirfd(dir), dent->d_name, &statbuf, AT_SYMLINK_NOFOLLOW) != 0)
57 if (S_ISLNK(statbuf.st_mode))
60 value = udev_device_get_sysattr_value(device, dent->d_name);
63 dbg(udev, "attr '%s'='%s'\n", dent->d_name, value);
65 /* skip nonprintable attributes */
67 while (len > 0 && isprint(value[len-1]))
70 dbg(udev, "attribute value of '%s' non-printable, skip\n", dent->d_name);
74 printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
81 static int print_device_chain(struct udev_device *device)
83 struct udev_device *device_parent;
87 "Udevadm info starts with the device specified by the devpath and then\n"
88 "walks up the chain of parent devices. It prints for every device\n"
89 "found, all possible attributes in the udev rules key format.\n"
90 "A rule to match, can be composed by the attributes of the device\n"
91 "and the attributes from one single parent device.\n"
94 printf(" looking at device '%s':\n", udev_device_get_devpath(device));
95 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device));
96 str = udev_device_get_subsystem(device);
99 printf(" SUBSYSTEM==\"%s\"\n", str);
100 str = udev_device_get_driver(device);
103 printf(" DRIVER==\"%s\"\n", str);
104 print_all_attributes(device, "ATTR");
106 device_parent = device;
108 device_parent = udev_device_get_parent(device_parent);
109 if (device_parent == NULL)
111 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent));
112 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent));
113 str = udev_device_get_subsystem(device_parent);
116 printf(" SUBSYSTEMS==\"%s\"\n", str);
117 str = udev_device_get_driver(device_parent);
120 printf(" DRIVERS==\"%s\"\n", str);
121 print_all_attributes(device_parent, "ATTRS");
122 } while (device_parent != NULL);
127 static void print_record(struct udev_device *device)
132 struct udev_list_entry *list_entry;
134 printf("P: %s\n", udev_device_get_devpath(device));
136 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
137 str = udev_device_get_devnode(device);
139 printf("N: %s\n", &str[len+1]);
141 i = udev_device_get_devlink_priority(device);
143 printf("L: %i\n", i);
145 i = udev_device_get_watch_handle(device);
147 printf("W: %u\n", i);
149 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
150 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
151 printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
154 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
156 udev_list_entry_get_name(list_entry),
157 udev_list_entry_get_value(list_entry));
161 static int stat_device(const char *name, int export, const char *prefix)
165 if (stat(name, &statbuf) != 0)
171 printf("%sMAJOR=%d\n"
173 prefix, major(statbuf.st_dev),
174 prefix, minor(statbuf.st_dev));
176 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
180 static int export_devices(struct udev *udev)
182 struct udev_enumerate *udev_enumerate;
183 struct udev_list_entry *list_entry;
185 udev_enumerate = udev_enumerate_new(udev);
186 if (udev_enumerate == NULL)
188 udev_enumerate_scan_devices(udev_enumerate);
189 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
190 struct udev_device *device;
192 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
193 if (device != NULL) {
194 print_record(device);
195 udev_device_unref(device);
198 udev_enumerate_unref(udev_enumerate);
202 int udevadm_info(struct udev *udev, int argc, char *argv[])
204 struct udev_device *device = NULL;
207 const char *export_prefix = NULL;
208 char path[UTIL_PATH_SIZE];
209 char name[UTIL_PATH_SIZE];
210 struct udev_list_entry *list_entry;
213 static const struct option options[] = {
214 { "name", required_argument, NULL, 'n' },
215 { "path", required_argument, NULL, 'p' },
216 { "query", required_argument, NULL, 'q' },
217 { "attribute-walk", no_argument, NULL, 'a' },
218 { "export-db", no_argument, NULL, 'e' },
219 { "root", no_argument, NULL, 'r' },
220 { "device-id-of-file", required_argument, NULL, 'd' },
221 { "export", no_argument, NULL, 'x' },
222 { "export-prefix", required_argument, NULL, 'P' },
223 { "version", no_argument, NULL, 'V' },
224 { "help", no_argument, NULL, 'h' },
231 ACTION_ATTRIBUTE_WALK,
233 ACTION_DEVICE_ID_FILE,
234 } action = ACTION_NONE;
243 } query = QUERY_NONE;
249 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
253 dbg(udev, "option '%c'\n", option);
256 if (device != NULL) {
257 fprintf(stderr, "device already specified\n");
261 /* remove /dev if given */
262 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0)
263 util_strscpyl(name, sizeof(name), udev_get_dev_path(udev), "/", optarg, NULL);
265 util_strscpy(name, sizeof(name), optarg);
266 util_remove_trailing_chars(name, '/');
267 if (stat(name, &statbuf) < 0) {
268 fprintf(stderr, "device node not found\n");
274 if (S_ISBLK(statbuf.st_mode)) {
276 } else if (S_ISCHR(statbuf.st_mode)) {
279 fprintf(stderr, "device node has wrong file type\n");
283 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
284 if (device == NULL) {
285 fprintf(stderr, "device node not found\n");
292 if (device != NULL) {
293 fprintf(stderr, "device already specified\n");
297 /* add sys dir if needed */
298 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
299 util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), optarg, NULL);
301 util_strscpy(path, sizeof(path), optarg);
302 util_remove_trailing_chars(path, '/');
303 device = udev_device_new_from_syspath(udev, path);
304 if (device == NULL) {
305 fprintf(stderr, "device path not found\n");
311 action = ACTION_QUERY;
312 if (strcmp(optarg, "property") == 0 || strcmp(optarg, "env") == 0) {
313 query = QUERY_PROPERTY;
314 } else if (strcmp(optarg, "name") == 0) {
316 } else if (strcmp(optarg, "symlink") == 0) {
317 query = QUERY_SYMLINK;
318 } else if (strcmp(optarg, "path") == 0) {
320 } else if (strcmp(optarg, "all") == 0) {
323 fprintf(stderr, "unknown query type\n");
329 if (action == ACTION_NONE)
330 action = ACTION_ROOT;
334 action = ACTION_DEVICE_ID_FILE;
335 util_strscpy(name, sizeof(name), optarg);
338 action = ACTION_ATTRIBUTE_WALK;
341 export_devices(udev);
347 export_prefix = optarg;
350 printf("%s\n", VERSION);
353 printf("Usage: udevadm info OPTIONS\n"
354 " --query=<type> query device information:\n"
355 " name name of device node\n"
356 " symlink pointing to node\n"
357 " path sys device path\n"
358 " property the device properties\n"
360 " --path=<syspath> sys device path used for query or attribute walk\n"
361 " --name=<name> node or symlink name used for query or attribute walk\n"
362 " --root prepend dev directory to path names\n"
363 " --attribute-walk print all key matches while walking along the chain\n"
364 " of parent devices\n"
365 " --device-id-of-file=<file> print major:minor of device containing this file\n"
366 " --export-db export the content of the udev database\n"
376 if (device == NULL) {
377 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
384 const char *node = udev_device_get_devnode(device);
387 fprintf(stderr, "no device node found\n");
393 printf("%s\n", udev_device_get_devnode(device));
395 size_t len = strlen(udev_get_dev_path(udev));
397 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
402 list_entry = udev_device_get_devlinks_list_entry(device);
403 while (list_entry != NULL) {
405 printf("%s", udev_list_entry_get_name(list_entry));
409 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
410 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
412 list_entry = udev_list_entry_get_next(list_entry);
413 if (list_entry != NULL)
419 printf("%s\n", udev_device_get_devpath(device));
422 list_entry = udev_device_get_properties_list_entry(device);
423 while (list_entry != NULL) {
424 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
425 list_entry = udev_list_entry_get_next(list_entry);
429 print_record(device);
432 fprintf(stderr, "unknown query type\n");
436 case ACTION_ATTRIBUTE_WALK:
437 if (device == NULL) {
438 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
442 print_device_chain(device);
444 case ACTION_DEVICE_ID_FILE:
445 if (stat_device(name, export, export_prefix) != 0)
449 printf("%s\n", udev_get_dev_path(udev));
452 fprintf(stderr, "missing option\n");
458 udev_device_unref(device);