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"
399 if (device == NULL) {
400 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
408 printf("%s\n", udev_device_get_devnode(device));
413 len = strlen(udev_get_dev_path(udev));
414 node = udev_device_get_devnode(device);
416 fprintf(stderr, "no device node found\n");
420 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
424 list_entry = udev_device_get_devlinks_list_entry(device);
425 while (list_entry != NULL) {
427 printf("%s", udev_list_entry_get_name(list_entry));
431 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
432 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
434 list_entry = udev_list_entry_get_next(list_entry);
435 if (list_entry != NULL)
441 printf("%s\n", udev_device_get_devpath(device));
444 list_entry = udev_device_get_properties_list_entry(device);
445 while (list_entry != NULL) {
446 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
447 list_entry = udev_list_entry_get_next(list_entry);
451 print_record(device);
454 fprintf(stderr, "unknown query type\n");
458 case ACTION_ATTRIBUTE_WALK:
459 if (device == NULL) {
460 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
464 print_device_chain(device);
466 case ACTION_DEVICE_ID_FILE:
467 if (stat_device(name, export, export_prefix) != 0)
471 printf("%s\n", udev_get_dev_path(udev));
474 fprintf(stderr, "missing option\n");
480 udev_device_unref(device);