2 * Copyright (C) 2004-2008 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/>.
29 #include <sys/types.h>
33 static void print_all_attributes(struct udev_device *device, const char *key)
35 struct udev *udev = udev_device_get_udev(device);
39 dir = opendir(udev_device_get_syspath(device));
41 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
43 char filename[UTIL_PATH_SIZE];
47 if (dent->d_name[0] == '.')
50 if (strcmp(dent->d_name, "uevent") == 0)
52 if (strcmp(dent->d_name, "dev") == 0)
55 util_strlcpy(filename, udev_device_get_syspath(device), sizeof(filename));
56 util_strlcat(filename, "/", sizeof(filename));
57 util_strlcat(filename, dent->d_name, sizeof(filename));
58 if (lstat(filename, &statbuf) != 0)
60 if (S_ISLNK(statbuf.st_mode))
63 value = udev_device_get_sysattr_value(device, dent->d_name);
66 dbg(udev, "attr '%s'='%s'(%zi)\n", dent->d_name, value, len);
68 /* skip nonprintable attributes */
70 while (len > 0 && isprint(value[len-1]))
73 dbg(udev, "attribute value of '%s' non-printable, skip\n", dent->d_name);
77 printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
84 static int print_device_chain(struct udev_device *device)
86 struct udev_device *device_parent;
90 "Udevadm info starts with the device specified by the devpath and then\n"
91 "walks up the chain of parent devices. It prints for every device\n"
92 "found, all possible attributes in the udev rules key format.\n"
93 "A rule to match, can be composed by the attributes of the device\n"
94 "and the attributes from one single parent device.\n"
97 printf(" looking at device '%s':\n", udev_device_get_devpath(device));
98 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device));
99 str = udev_device_get_subsystem(device);
102 printf(" SUBSYSTEM==\"%s\"\n", str);
103 str = udev_device_get_driver(device);
106 printf(" DRIVER==\"%s\"\n", str);
107 print_all_attributes(device, "ATTR");
109 device_parent = device;
111 device_parent = udev_device_get_parent(device_parent);
112 if (device_parent == NULL)
114 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent));
115 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent));
116 str = udev_device_get_subsystem(device_parent);
119 printf(" SUBSYSTEMS==\"%s\"\n", str);
120 str = udev_device_get_driver(device_parent);
123 printf(" DRIVERS==\"%s\"\n", str);
124 print_all_attributes(device_parent, "ATTRS");
125 } while (device_parent != NULL);
130 static void print_record(struct udev_device *device)
135 struct udev_list_entry *list_entry;
137 printf("P: %s\n", udev_device_get_devpath(device));
139 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
140 str = udev_device_get_devnode(device);
142 printf("N: %s\n", &str[len+1]);
144 i = udev_device_get_devlink_priority(device);
146 printf("L: %i\n", i);
148 i = udev_device_get_num_fake_partitions(device);
152 i = udev_device_get_ignore_remove(device);
156 i = udev_device_get_watch_handle(device);
160 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
161 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
162 printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
165 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
167 udev_list_entry_get_name(list_entry),
168 udev_list_entry_get_value(list_entry));
172 static int stat_device(const char *name, int export, const char *prefix)
176 if (stat(name, &statbuf) != 0)
182 printf("%sMAJOR=%d\n"
184 prefix, major(statbuf.st_dev),
185 prefix, minor(statbuf.st_dev));
187 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
191 static int export_devices(struct udev *udev)
193 struct udev_enumerate *udev_enumerate;
194 struct udev_list_entry *list_entry;
196 udev_enumerate = udev_enumerate_new(udev);
197 if (udev_enumerate == NULL)
199 udev_enumerate_scan_devices(udev_enumerate);
200 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
201 struct udev_device *device;
203 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
204 if (device != NULL) {
205 if (udev_device_get_devnode(device) != NULL)
206 print_record(device);
207 udev_device_unref(device);
210 udev_enumerate_unref(udev_enumerate);
214 int udevadm_info(struct udev *udev, int argc, char *argv[])
216 struct udev_device *device = NULL;
219 const char *export_prefix = NULL;
220 char path[UTIL_PATH_SIZE];
221 char name[UTIL_PATH_SIZE];
222 struct udev_list_entry *list_entry;
225 static const struct option options[] = {
226 { "name", required_argument, NULL, 'n' },
227 { "path", required_argument, NULL, 'p' },
228 { "query", required_argument, NULL, 'q' },
229 { "attribute-walk", no_argument, NULL, 'a' },
230 { "export-db", no_argument, NULL, 'e' },
231 { "root", no_argument, NULL, 'r' },
232 { "device-id-of-file", required_argument, NULL, 'd' },
233 { "export", no_argument, NULL, 'x' },
234 { "export-prefix", required_argument, NULL, 'P' },
235 { "version", no_argument, NULL, 'V' },
236 { "help", no_argument, NULL, 'h' },
243 ACTION_ATTRIBUTE_WALK,
245 ACTION_DEVICE_ID_FILE,
246 } action = ACTION_NONE;
255 } query = QUERY_NONE;
261 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
265 dbg(udev, "option '%c'\n", option);
268 if (device != NULL) {
269 fprintf(stderr, "device already specified\n");
273 /* remove /dev if given */
274 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0) {
275 util_strlcpy(name, udev_get_dev_path(udev), sizeof(name));
276 util_strlcat(name, "/", sizeof(name));
277 util_strlcat(name, optarg, sizeof(name));
279 util_strlcpy(name, optarg, sizeof(name));
281 util_remove_trailing_chars(name, '/');
282 if (stat(name, &statbuf) < 0) {
283 fprintf(stderr, "device node not found\n");
289 if (S_ISBLK(statbuf.st_mode)) {
291 } else if (S_ISCHR(statbuf.st_mode)) {
294 fprintf(stderr, "device node has wrong file type\n");
298 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
299 if (device == NULL) {
300 fprintf(stderr, "device node not found\n");
307 if (device != NULL) {
308 fprintf(stderr, "device already specified\n");
312 /* add sys dir if needed */
313 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0) {
314 util_strlcpy(path, udev_get_sys_path(udev), sizeof(path));
315 util_strlcat(path, optarg, sizeof(path));
317 util_strlcpy(path, optarg, sizeof(path));
319 util_remove_trailing_chars(path, '/');
320 device = udev_device_new_from_syspath(udev, path);
321 if (device == NULL) {
322 fprintf(stderr, "device path not found\n");
328 action = ACTION_QUERY;
329 if (strcmp(optarg, "name") == 0) {
333 if (strcmp(optarg, "symlink") == 0) {
334 query = QUERY_SYMLINK;
337 if (strcmp(optarg, "path") == 0) {
341 if (strcmp(optarg, "env") == 0) {
345 if (strcmp(optarg, "all") == 0) {
349 fprintf(stderr, "unknown query type\n");
353 if (action == ACTION_NONE)
354 action = ACTION_ROOT;
358 action = ACTION_DEVICE_ID_FILE;
359 util_strlcpy(name, optarg, sizeof(name));
362 action = ACTION_ATTRIBUTE_WALK;
365 export_devices(udev);
371 export_prefix = optarg;
374 printf("%s\n", VERSION);
377 printf("Usage: udevadm info OPTIONS\n"
378 " --query=<type> query device information:\n"
379 " name name of device node\n"
380 " symlink pointing to node\n"
381 " path sys device path\n"
382 " env the device related imported environment\n"
384 " --path=<syspath> sys device path used for query or attribute walk\n"
385 " --name=<name> node or symlink name used for query or attribute walk\n"
386 " --root prepend dev directory to path names\n"
387 " --attribute-walk print all key matches while walking along the chain\n"
388 " of parent devices\n"
389 " --device-id-of-file=<file> print major:minor of device containing this file\n"
390 " --export-db export the content of the udev database\n"
391 " --help print this text\n"
401 if (device == NULL) {
402 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
410 printf("%s\n", udev_device_get_devnode(device));
415 len = strlen(udev_get_dev_path(udev));
416 node = udev_device_get_devnode(device);
418 fprintf(stderr, "no device node found\n");
422 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
426 list_entry = udev_device_get_devlinks_list_entry(device);
427 while (list_entry != NULL) {
429 printf("%s", udev_list_entry_get_name(list_entry));
433 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
434 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
436 list_entry = udev_list_entry_get_next(list_entry);
437 if (list_entry != NULL)
443 printf("%s\n", udev_device_get_devpath(device));
446 list_entry = udev_device_get_properties_list_entry(device);
447 while (list_entry != NULL) {
448 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
449 list_entry = udev_list_entry_get_next(list_entry);
453 print_record(device);
456 fprintf(stderr, "unknown query type\n");
460 case ACTION_ATTRIBUTE_WALK:
461 if (device == NULL) {
462 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
466 print_device_chain(device);
468 case ACTION_DEVICE_ID_FILE:
469 if (stat_device(name, export, export_prefix) != 0)
473 printf("%s\n", udev_get_dev_path(udev));
476 fprintf(stderr, "missing option\n");
482 udev_device_unref(device);