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 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
146 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
147 printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
150 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
152 udev_list_entry_get_name(list_entry),
153 udev_list_entry_get_value(list_entry));
157 static int stat_device(const char *name, int export, const char *prefix)
161 if (stat(name, &statbuf) != 0)
167 printf("%sMAJOR=%d\n"
169 prefix, major(statbuf.st_dev),
170 prefix, minor(statbuf.st_dev));
172 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
176 static int export_devices(struct udev *udev)
178 struct udev_enumerate *udev_enumerate;
179 struct udev_list_entry *list_entry;
181 udev_enumerate = udev_enumerate_new(udev);
182 if (udev_enumerate == NULL)
184 udev_enumerate_scan_devices(udev_enumerate);
185 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
186 struct udev_device *device;
188 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
189 if (device != NULL) {
190 print_record(device);
191 udev_device_unref(device);
194 udev_enumerate_unref(udev_enumerate);
198 int udevadm_info(struct udev *udev, int argc, char *argv[])
200 struct udev_device *device = NULL;
203 const char *export_prefix = NULL;
204 char path[UTIL_PATH_SIZE];
205 char name[UTIL_PATH_SIZE];
206 struct udev_list_entry *list_entry;
209 static const struct option options[] = {
210 { "name", required_argument, NULL, 'n' },
211 { "path", required_argument, NULL, 'p' },
212 { "query", required_argument, NULL, 'q' },
213 { "attribute-walk", no_argument, NULL, 'a' },
214 { "export-db", no_argument, NULL, 'e' },
215 { "root", no_argument, NULL, 'r' },
216 { "device-id-of-file", required_argument, NULL, 'd' },
217 { "export", no_argument, NULL, 'x' },
218 { "export-prefix", required_argument, NULL, 'P' },
219 { "version", no_argument, NULL, 'V' },
220 { "help", no_argument, NULL, 'h' },
227 ACTION_ATTRIBUTE_WALK,
229 ACTION_DEVICE_ID_FILE,
230 } action = ACTION_NONE;
239 } query = QUERY_NONE;
245 option = getopt_long(argc, argv, "aed:n:p:q:rxP:Vh", options, NULL);
249 dbg(udev, "option '%c'\n", option);
252 if (device != NULL) {
253 fprintf(stderr, "device already specified\n");
257 /* remove /dev if given */
258 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0)
259 util_strscpyl(name, sizeof(name), udev_get_dev_path(udev), "/", optarg, NULL);
261 util_strscpy(name, sizeof(name), optarg);
262 util_remove_trailing_chars(name, '/');
263 if (stat(name, &statbuf) < 0) {
264 fprintf(stderr, "device node not found\n");
270 if (S_ISBLK(statbuf.st_mode)) {
272 } else if (S_ISCHR(statbuf.st_mode)) {
275 fprintf(stderr, "device node has wrong file type\n");
279 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
280 if (device == NULL) {
281 fprintf(stderr, "device node not found\n");
288 if (device != NULL) {
289 fprintf(stderr, "device already specified\n");
293 /* add sys dir if needed */
294 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
295 util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), optarg, NULL);
297 util_strscpy(path, sizeof(path), optarg);
298 util_remove_trailing_chars(path, '/');
299 device = udev_device_new_from_syspath(udev, path);
300 if (device == NULL) {
301 fprintf(stderr, "device path not found\n");
307 action = ACTION_QUERY;
308 if (strcmp(optarg, "property") == 0 || strcmp(optarg, "env") == 0) {
309 query = QUERY_PROPERTY;
310 } else if (strcmp(optarg, "name") == 0) {
312 } else if (strcmp(optarg, "symlink") == 0) {
313 query = QUERY_SYMLINK;
314 } else if (strcmp(optarg, "path") == 0) {
316 } else if (strcmp(optarg, "all") == 0) {
319 fprintf(stderr, "unknown query type\n");
325 if (action == ACTION_NONE)
326 action = ACTION_ROOT;
330 action = ACTION_DEVICE_ID_FILE;
331 util_strscpy(name, sizeof(name), optarg);
334 action = ACTION_ATTRIBUTE_WALK;
337 export_devices(udev);
343 export_prefix = optarg;
346 printf("%s\n", VERSION);
349 printf("Usage: udevadm info OPTIONS\n"
350 " --query=<type> query device information:\n"
351 " name name of device node\n"
352 " symlink pointing to node\n"
353 " path sys device path\n"
354 " property the device properties\n"
356 " --path=<syspath> sys device path used for query or attribute walk\n"
357 " --name=<name> node or symlink name used for query or attribute walk\n"
358 " --root prepend dev directory to path names\n"
359 " --attribute-walk print all key matches while walking along the chain\n"
360 " of parent devices\n"
361 " --device-id-of-file=<file> print major:minor of device containing this file\n"
362 " --export-db export the content of the udev database\n"
372 if (device == NULL) {
373 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
380 const char *node = udev_device_get_devnode(device);
383 fprintf(stderr, "no device node found\n");
389 printf("%s\n", udev_device_get_devnode(device));
391 size_t len = strlen(udev_get_dev_path(udev));
393 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
398 list_entry = udev_device_get_devlinks_list_entry(device);
399 while (list_entry != NULL) {
401 printf("%s", udev_list_entry_get_name(list_entry));
405 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
406 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
408 list_entry = udev_list_entry_get_next(list_entry);
409 if (list_entry != NULL)
415 printf("%s\n", udev_device_get_devpath(device));
418 list_entry = udev_device_get_properties_list_entry(device);
419 while (list_entry != NULL) {
420 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
421 list_entry = udev_list_entry_get_next(list_entry);
425 print_record(device);
428 fprintf(stderr, "unknown query type\n");
432 case ACTION_ATTRIBUTE_WALK:
433 if (device == NULL) {
434 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
438 print_device_chain(device);
440 case ACTION_DEVICE_ID_FILE:
441 if (stat_device(name, export, export_prefix) != 0)
445 printf("%s\n", udev_get_dev_path(udev));
448 fprintf(stderr, "missing option\n");
454 udev_device_unref(device);