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 bool skip_attribute(const char *name)
36 static const char const *skip[] = {
47 for (i = 0; i < ARRAY_SIZE(skip); i++)
48 if (strcmp(name, skip[i]) == 0)
53 static void print_all_attributes(struct udev_device *device, const char *key)
55 struct udev_list_entry *sysattr;
57 udev_list_entry_foreach(sysattr, udev_device_get_sysattr_list_entry(device)) {
58 struct udev *udev = udev_device_get_udev(device);
63 name = udev_list_entry_get_name(sysattr);
64 if (skip_attribute(name))
67 value = udev_device_get_sysattr_value(device, name);
70 dbg(udev, "attr '%s'='%s'\n", name, value);
72 /* skip nonprintable attributes */
74 while (len > 0 && isprint(value[len-1]))
77 dbg(udev, "attribute value of '%s' non-printable, skip\n", name);
81 printf(" %s{%s}==\"%s\"\n", key, name, value);
86 static int print_device_chain(struct udev_device *device)
88 struct udev_device *device_parent;
92 "Udevadm info starts with the device specified by the devpath and then\n"
93 "walks up the chain of parent devices. It prints for every device\n"
94 "found, all possible attributes in the udev rules key format.\n"
95 "A rule to match, can be composed by the attributes of the device\n"
96 "and the attributes from one single parent device.\n"
99 printf(" looking at device '%s':\n", udev_device_get_devpath(device));
100 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device));
101 str = udev_device_get_subsystem(device);
104 printf(" SUBSYSTEM==\"%s\"\n", str);
105 str = udev_device_get_driver(device);
108 printf(" DRIVER==\"%s\"\n", str);
109 print_all_attributes(device, "ATTR");
111 device_parent = device;
113 device_parent = udev_device_get_parent(device_parent);
114 if (device_parent == NULL)
116 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent));
117 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent));
118 str = udev_device_get_subsystem(device_parent);
121 printf(" SUBSYSTEMS==\"%s\"\n", str);
122 str = udev_device_get_driver(device_parent);
125 printf(" DRIVERS==\"%s\"\n", str);
126 print_all_attributes(device_parent, "ATTRS");
127 } while (device_parent != NULL);
132 static void print_record(struct udev_device *device)
137 struct udev_list_entry *list_entry;
139 printf("P: %s\n", udev_device_get_devpath(device));
141 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
142 str = udev_device_get_devnode(device);
144 printf("N: %s\n", &str[len+1]);
146 i = udev_device_get_devlink_priority(device);
148 printf("L: %i\n", i);
150 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
151 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
152 printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
155 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
157 udev_list_entry_get_name(list_entry),
158 udev_list_entry_get_value(list_entry));
162 static int stat_device(const char *name, bool export, const char *prefix)
166 if (stat(name, &statbuf) != 0)
172 printf("%sMAJOR=%d\n"
174 prefix, major(statbuf.st_dev),
175 prefix, minor(statbuf.st_dev));
177 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
181 static int export_devices(struct udev *udev)
183 struct udev_enumerate *udev_enumerate;
184 struct udev_list_entry *list_entry;
186 udev_enumerate = udev_enumerate_new(udev);
187 if (udev_enumerate == NULL)
189 udev_enumerate_scan_devices(udev_enumerate);
190 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
191 struct udev_device *device;
193 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
194 if (device != NULL) {
195 print_record(device);
196 udev_device_unref(device);
199 udev_enumerate_unref(udev_enumerate);
203 int udevadm_info(struct udev *udev, int argc, char *argv[])
205 struct udev_device *device = NULL;
208 const char *export_prefix = NULL;
209 char path[UTIL_PATH_SIZE];
210 char name[UTIL_PATH_SIZE];
211 struct udev_list_entry *list_entry;
214 static const struct option options[] = {
215 { "name", required_argument, NULL, 'n' },
216 { "path", required_argument, NULL, 'p' },
217 { "query", required_argument, NULL, 'q' },
218 { "attribute-walk", no_argument, NULL, 'a' },
219 { "export-db", no_argument, NULL, 'e' },
220 { "root", no_argument, NULL, 'r' },
221 { "device-id-of-file", required_argument, NULL, 'd' },
222 { "export", no_argument, NULL, 'x' },
223 { "export-prefix", required_argument, NULL, 'P' },
224 { "version", no_argument, NULL, 'V' },
225 { "help", no_argument, NULL, 'h' },
232 ACTION_ATTRIBUTE_WALK,
234 ACTION_DEVICE_ID_FILE,
235 } action = ACTION_NONE;
244 } query = QUERY_NONE;
250 option = getopt_long(argc, argv, "aed:n:p:q:rxP:Vh", options, NULL);
254 dbg(udev, "option '%c'\n", option);
257 if (device != NULL) {
258 fprintf(stderr, "device already specified\n");
262 /* remove /dev if given */
263 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0)
264 util_strscpyl(name, sizeof(name), udev_get_dev_path(udev), "/", optarg, NULL);
266 util_strscpy(name, sizeof(name), optarg);
267 util_remove_trailing_chars(name, '/');
268 if (stat(name, &statbuf) < 0) {
269 fprintf(stderr, "device node not found\n");
275 if (S_ISBLK(statbuf.st_mode)) {
277 } else if (S_ISCHR(statbuf.st_mode)) {
280 fprintf(stderr, "device node has wrong file type\n");
284 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
285 if (device == NULL) {
286 fprintf(stderr, "device node not found\n");
293 if (device != NULL) {
294 fprintf(stderr, "device already specified\n");
298 /* add sys dir if needed */
299 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
300 util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), optarg, NULL);
302 util_strscpy(path, sizeof(path), optarg);
303 util_remove_trailing_chars(path, '/');
304 device = udev_device_new_from_syspath(udev, path);
305 if (device == NULL) {
306 fprintf(stderr, "device path not found\n");
312 action = ACTION_QUERY;
313 if (strcmp(optarg, "property") == 0 || strcmp(optarg, "env") == 0) {
314 query = QUERY_PROPERTY;
315 } else if (strcmp(optarg, "name") == 0) {
317 } else if (strcmp(optarg, "symlink") == 0) {
318 query = QUERY_SYMLINK;
319 } else if (strcmp(optarg, "path") == 0) {
321 } else if (strcmp(optarg, "all") == 0) {
324 fprintf(stderr, "unknown query type\n");
330 if (action == ACTION_NONE)
331 action = ACTION_ROOT;
335 action = ACTION_DEVICE_ID_FILE;
336 util_strscpy(name, sizeof(name), optarg);
339 action = ACTION_ATTRIBUTE_WALK;
342 export_devices(udev);
348 export_prefix = optarg;
351 printf("%s\n", VERSION);
354 printf("Usage: udevadm info OPTIONS\n"
355 " --query=<type> query device information:\n"
356 " name name of device node\n"
357 " symlink pointing to node\n"
358 " path sys device path\n"
359 " property the device properties\n"
361 " --path=<syspath> sys device path used for query or attribute walk\n"
362 " --name=<name> node or symlink name used for query or attribute walk\n"
363 " --root prepend dev directory to path names\n"
364 " --attribute-walk print all key matches while walking along the chain\n"
365 " of parent devices\n"
366 " --device-id-of-file=<file> print major:minor of device containing this file\n"
367 " --export export key/value pairs\n"
368 " --export-prefix export the key name with a prefix\n"
369 " --export-db export the content of the udev database\n"
379 if (device == NULL) {
380 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
387 const char *node = udev_device_get_devnode(device);
390 fprintf(stderr, "no device node found\n");
396 printf("%s\n", udev_device_get_devnode(device));
398 size_t len = strlen(udev_get_dev_path(udev));
400 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
405 list_entry = udev_device_get_devlinks_list_entry(device);
406 while (list_entry != NULL) {
408 printf("%s", udev_list_entry_get_name(list_entry));
412 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
413 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
415 list_entry = udev_list_entry_get_next(list_entry);
416 if (list_entry != NULL)
422 printf("%s\n", udev_device_get_devpath(device));
425 list_entry = udev_device_get_properties_list_entry(device);
426 while (list_entry != NULL) {
428 const char *prefix = export_prefix;
432 printf("%s%s='%s'\n", prefix,
433 udev_list_entry_get_name(list_entry),
434 udev_list_entry_get_value(list_entry));
436 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
438 list_entry = udev_list_entry_get_next(list_entry);
442 print_record(device);
445 fprintf(stderr, "unknown query type\n");
449 case ACTION_ATTRIBUTE_WALK:
450 if (device == NULL) {
451 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
455 print_device_chain(device);
457 case ACTION_DEVICE_ID_FILE:
458 if (stat_device(name, export, export_prefix) != 0)
462 printf("%s\n", udev_get_dev_path(udev));
465 fprintf(stderr, "missing option\n");
471 udev_device_unref(device);