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'(%zi)\n", dent->d_name, value, len);
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 i = udev_device_get_num_fake_partitions(device);
147 printf("A: %u\n", i);
149 i = udev_device_get_ignore_remove(device);
151 printf("R: %u\n", i);
153 i = udev_device_get_watch_handle(device);
155 printf("W: %u\n", i);
157 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
158 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
159 printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
162 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
164 udev_list_entry_get_name(list_entry),
165 udev_list_entry_get_value(list_entry));
169 static int stat_device(const char *name, int export, const char *prefix)
173 if (stat(name, &statbuf) != 0)
179 printf("%sMAJOR=%d\n"
181 prefix, major(statbuf.st_dev),
182 prefix, minor(statbuf.st_dev));
184 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
188 static int export_devices(struct udev *udev)
190 struct udev_enumerate *udev_enumerate;
191 struct udev_list_entry *list_entry;
193 udev_enumerate = udev_enumerate_new(udev);
194 if (udev_enumerate == NULL)
196 udev_enumerate_scan_devices(udev_enumerate);
197 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
198 struct udev_device *device;
200 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
201 if (device != NULL) {
202 print_record(device);
203 udev_device_unref(device);
206 udev_enumerate_unref(udev_enumerate);
210 int udevadm_info(struct udev *udev, int argc, char *argv[])
212 struct udev_device *device = NULL;
215 const char *export_prefix = NULL;
216 char path[UTIL_PATH_SIZE];
217 char name[UTIL_PATH_SIZE];
218 struct udev_list_entry *list_entry;
221 static const struct option options[] = {
222 { "name", required_argument, NULL, 'n' },
223 { "path", required_argument, NULL, 'p' },
224 { "query", required_argument, NULL, 'q' },
225 { "attribute-walk", no_argument, NULL, 'a' },
226 { "export-db", no_argument, NULL, 'e' },
227 { "root", no_argument, NULL, 'r' },
228 { "device-id-of-file", required_argument, NULL, 'd' },
229 { "export", no_argument, NULL, 'x' },
230 { "export-prefix", required_argument, NULL, 'P' },
231 { "version", no_argument, NULL, 'V' },
232 { "help", no_argument, NULL, 'h' },
239 ACTION_ATTRIBUTE_WALK,
241 ACTION_DEVICE_ID_FILE,
242 } action = ACTION_NONE;
251 } query = QUERY_NONE;
257 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
261 dbg(udev, "option '%c'\n", option);
264 if (device != NULL) {
265 fprintf(stderr, "device already specified\n");
269 /* remove /dev if given */
270 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0)
271 util_strscpyl(name, sizeof(name), udev_get_dev_path(udev), "/", optarg, NULL);
273 util_strscpy(name, sizeof(name), optarg);
274 util_remove_trailing_chars(name, '/');
275 if (stat(name, &statbuf) < 0) {
276 fprintf(stderr, "device node not found\n");
282 if (S_ISBLK(statbuf.st_mode)) {
284 } else if (S_ISCHR(statbuf.st_mode)) {
287 fprintf(stderr, "device node has wrong file type\n");
291 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
292 if (device == NULL) {
293 fprintf(stderr, "device node not found\n");
300 if (device != NULL) {
301 fprintf(stderr, "device already specified\n");
305 /* add sys dir if needed */
306 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
307 util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), optarg, NULL);
309 util_strscpy(path, sizeof(path), optarg);
310 util_remove_trailing_chars(path, '/');
311 device = udev_device_new_from_syspath(udev, path);
312 if (device == NULL) {
313 fprintf(stderr, "device path not found\n");
319 action = ACTION_QUERY;
320 if (strcmp(optarg, "property") == 0 || strcmp(optarg, "env") == 0) {
321 query = QUERY_PROPERTY;
322 } else if (strcmp(optarg, "name") == 0) {
324 } else if (strcmp(optarg, "symlink") == 0) {
325 query = QUERY_SYMLINK;
326 } else if (strcmp(optarg, "path") == 0) {
328 } else if (strcmp(optarg, "all") == 0) {
331 fprintf(stderr, "unknown query type\n");
337 if (action == ACTION_NONE)
338 action = ACTION_ROOT;
342 action = ACTION_DEVICE_ID_FILE;
343 util_strscpy(name, sizeof(name), optarg);
346 action = ACTION_ATTRIBUTE_WALK;
349 export_devices(udev);
355 export_prefix = optarg;
358 printf("%s\n", VERSION);
361 printf("Usage: udevadm info OPTIONS\n"
362 " --query=<type> query device information:\n"
363 " name name of device node\n"
364 " symlink pointing to node\n"
365 " path sys device path\n"
366 " property the device properties\n"
368 " --path=<syspath> sys device path used for query or attribute walk\n"
369 " --name=<name> node or symlink name used for query or attribute walk\n"
370 " --root prepend dev directory to path names\n"
371 " --attribute-walk print all key matches while walking along the chain\n"
372 " of parent devices\n"
373 " --device-id-of-file=<file> print major:minor of device containing this file\n"
374 " --export-db export the content of the udev database\n"
384 if (device == NULL) {
385 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
393 printf("%s\n", udev_device_get_devnode(device));
398 len = strlen(udev_get_dev_path(udev));
399 node = udev_device_get_devnode(device);
401 fprintf(stderr, "no device node found\n");
405 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
409 list_entry = udev_device_get_devlinks_list_entry(device);
410 while (list_entry != NULL) {
412 printf("%s", udev_list_entry_get_name(list_entry));
416 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
417 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
419 list_entry = udev_list_entry_get_next(list_entry);
420 if (list_entry != NULL)
426 printf("%s\n", udev_device_get_devpath(device));
429 list_entry = udev_device_get_properties_list_entry(device);
430 while (list_entry != NULL) {
431 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
432 list_entry = udev_list_entry_get_next(list_entry);
436 print_record(device);
439 fprintf(stderr, "unknown query type\n");
443 case ACTION_ATTRIBUTE_WALK:
444 if (device == NULL) {
445 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
449 print_device_chain(device);
451 case ACTION_DEVICE_ID_FILE:
452 if (stat_device(name, export, export_prefix) != 0)
456 printf("%s\n", udev_get_dev_path(udev));
459 fprintf(stderr, "missing option\n");
465 udev_device_unref(device);