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 print_record(device);
206 udev_device_unref(device);
209 udev_enumerate_unref(udev_enumerate);
213 int udevadm_info(struct udev *udev, int argc, char *argv[])
215 struct udev_device *device = NULL;
218 const char *export_prefix = NULL;
219 char path[UTIL_PATH_SIZE];
220 char name[UTIL_PATH_SIZE];
221 struct udev_list_entry *list_entry;
224 static const struct option options[] = {
225 { "name", required_argument, NULL, 'n' },
226 { "path", required_argument, NULL, 'p' },
227 { "query", required_argument, NULL, 'q' },
228 { "attribute-walk", no_argument, NULL, 'a' },
229 { "export-db", no_argument, NULL, 'e' },
230 { "root", no_argument, NULL, 'r' },
231 { "device-id-of-file", required_argument, NULL, 'd' },
232 { "export", no_argument, NULL, 'x' },
233 { "export-prefix", required_argument, NULL, 'P' },
234 { "version", no_argument, NULL, 'V' },
235 { "help", no_argument, NULL, 'h' },
242 ACTION_ATTRIBUTE_WALK,
244 ACTION_DEVICE_ID_FILE,
245 } action = ACTION_NONE;
254 } query = QUERY_NONE;
260 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
264 dbg(udev, "option '%c'\n", option);
267 if (device != NULL) {
268 fprintf(stderr, "device already specified\n");
272 /* remove /dev if given */
273 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0) {
274 util_strlcpy(name, udev_get_dev_path(udev), sizeof(name));
275 util_strlcat(name, "/", sizeof(name));
276 util_strlcat(name, optarg, sizeof(name));
278 util_strlcpy(name, optarg, sizeof(name));
280 util_remove_trailing_chars(name, '/');
281 if (stat(name, &statbuf) < 0) {
282 fprintf(stderr, "device node not found\n");
288 if (S_ISBLK(statbuf.st_mode)) {
290 } else if (S_ISCHR(statbuf.st_mode)) {
293 fprintf(stderr, "device node has wrong file type\n");
297 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
298 if (device == NULL) {
299 fprintf(stderr, "device node not found\n");
306 if (device != NULL) {
307 fprintf(stderr, "device already specified\n");
311 /* add sys dir if needed */
312 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0) {
313 util_strlcpy(path, udev_get_sys_path(udev), sizeof(path));
314 util_strlcat(path, optarg, sizeof(path));
316 util_strlcpy(path, optarg, sizeof(path));
318 util_remove_trailing_chars(path, '/');
319 device = udev_device_new_from_syspath(udev, path);
320 if (device == NULL) {
321 fprintf(stderr, "device path not found\n");
327 action = ACTION_QUERY;
328 if (strcmp(optarg, "name") == 0) {
332 if (strcmp(optarg, "symlink") == 0) {
333 query = QUERY_SYMLINK;
336 if (strcmp(optarg, "path") == 0) {
340 if (strcmp(optarg, "env") == 0) {
344 if (strcmp(optarg, "all") == 0) {
348 fprintf(stderr, "unknown query type\n");
352 if (action == ACTION_NONE)
353 action = ACTION_ROOT;
357 action = ACTION_DEVICE_ID_FILE;
358 util_strlcpy(name, optarg, sizeof(name));
361 action = ACTION_ATTRIBUTE_WALK;
364 export_devices(udev);
370 export_prefix = optarg;
373 printf("%s\n", VERSION);
376 printf("Usage: udevadm info OPTIONS\n"
377 " --query=<type> query device information:\n"
378 " name name of device node\n"
379 " symlink pointing to node\n"
380 " path sys device path\n"
381 " env the device related imported environment\n"
383 " --path=<syspath> sys device path used for query or attribute walk\n"
384 " --name=<name> node or symlink name used for query or attribute walk\n"
385 " --root prepend dev directory to path names\n"
386 " --attribute-walk print all key matches while walking along the chain\n"
387 " of parent devices\n"
388 " --device-id-of-file=<file> print major:minor of device containing this file\n"
389 " --export-db export the content of the udev database\n"
390 " --help print this text\n"
400 if (device == NULL) {
401 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
409 printf("%s\n", udev_device_get_devnode(device));
414 len = strlen(udev_get_dev_path(udev));
415 node = udev_device_get_devnode(device);
417 fprintf(stderr, "no device node found\n");
421 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
425 list_entry = udev_device_get_devlinks_list_entry(device);
426 while (list_entry != NULL) {
428 printf("%s", udev_list_entry_get_name(list_entry));
432 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
433 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
435 list_entry = udev_list_entry_get_next(list_entry);
436 if (list_entry != NULL)
442 printf("%s\n", udev_device_get_devpath(device));
445 list_entry = udev_device_get_properties_list_entry(device);
446 while (list_entry != NULL) {
447 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
448 list_entry = udev_list_entry_get_next(list_entry);
452 print_record(device);
455 fprintf(stderr, "unknown query type\n");
459 case ACTION_ATTRIBUTE_WALK:
460 if (device == NULL) {
461 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
465 print_device_chain(device);
467 case ACTION_DEVICE_ID_FILE:
468 if (stat_device(name, export, export_prefix) != 0)
472 printf("%s\n", udev_get_dev_path(udev));
475 fprintf(stderr, "missing option\n");
481 udev_device_unref(device);