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 i = udev_device_get_ignore_remove(device);
147 printf("R: %u\n", i);
149 i = udev_device_get_watch_handle(device);
151 printf("W: %u\n", i);
153 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
154 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
155 printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
158 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
160 udev_list_entry_get_name(list_entry),
161 udev_list_entry_get_value(list_entry));
165 static int stat_device(const char *name, int export, const char *prefix)
169 if (stat(name, &statbuf) != 0)
175 printf("%sMAJOR=%d\n"
177 prefix, major(statbuf.st_dev),
178 prefix, minor(statbuf.st_dev));
180 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
184 static int export_devices(struct udev *udev)
186 struct udev_enumerate *udev_enumerate;
187 struct udev_list_entry *list_entry;
189 udev_enumerate = udev_enumerate_new(udev);
190 if (udev_enumerate == NULL)
192 udev_enumerate_scan_devices(udev_enumerate);
193 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
194 struct udev_device *device;
196 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
197 if (device != NULL) {
198 print_record(device);
199 udev_device_unref(device);
202 udev_enumerate_unref(udev_enumerate);
206 int udevadm_info(struct udev *udev, int argc, char *argv[])
208 struct udev_device *device = NULL;
211 const char *export_prefix = NULL;
212 char path[UTIL_PATH_SIZE];
213 char name[UTIL_PATH_SIZE];
214 struct udev_list_entry *list_entry;
217 static const struct option options[] = {
218 { "name", required_argument, NULL, 'n' },
219 { "path", required_argument, NULL, 'p' },
220 { "query", required_argument, NULL, 'q' },
221 { "attribute-walk", no_argument, NULL, 'a' },
222 { "export-db", no_argument, NULL, 'e' },
223 { "root", no_argument, NULL, 'r' },
224 { "device-id-of-file", required_argument, NULL, 'd' },
225 { "export", no_argument, NULL, 'x' },
226 { "export-prefix", required_argument, NULL, 'P' },
227 { "version", no_argument, NULL, 'V' },
228 { "help", no_argument, NULL, 'h' },
235 ACTION_ATTRIBUTE_WALK,
237 ACTION_DEVICE_ID_FILE,
238 } action = ACTION_NONE;
247 } query = QUERY_NONE;
253 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
257 dbg(udev, "option '%c'\n", option);
260 if (device != NULL) {
261 fprintf(stderr, "device already specified\n");
265 /* remove /dev if given */
266 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0)
267 util_strscpyl(name, sizeof(name), udev_get_dev_path(udev), "/", optarg, NULL);
269 util_strscpy(name, sizeof(name), optarg);
270 util_remove_trailing_chars(name, '/');
271 if (stat(name, &statbuf) < 0) {
272 fprintf(stderr, "device node not found\n");
278 if (S_ISBLK(statbuf.st_mode)) {
280 } else if (S_ISCHR(statbuf.st_mode)) {
283 fprintf(stderr, "device node has wrong file type\n");
287 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
288 if (device == NULL) {
289 fprintf(stderr, "device node not found\n");
296 if (device != NULL) {
297 fprintf(stderr, "device already specified\n");
301 /* add sys dir if needed */
302 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
303 util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), optarg, NULL);
305 util_strscpy(path, sizeof(path), optarg);
306 util_remove_trailing_chars(path, '/');
307 device = udev_device_new_from_syspath(udev, path);
308 if (device == NULL) {
309 fprintf(stderr, "device path not found\n");
315 action = ACTION_QUERY;
316 if (strcmp(optarg, "property") == 0 || strcmp(optarg, "env") == 0) {
317 query = QUERY_PROPERTY;
318 } else if (strcmp(optarg, "name") == 0) {
320 } else if (strcmp(optarg, "symlink") == 0) {
321 query = QUERY_SYMLINK;
322 } else if (strcmp(optarg, "path") == 0) {
324 } else if (strcmp(optarg, "all") == 0) {
327 fprintf(stderr, "unknown query type\n");
333 if (action == ACTION_NONE)
334 action = ACTION_ROOT;
338 action = ACTION_DEVICE_ID_FILE;
339 util_strscpy(name, sizeof(name), optarg);
342 action = ACTION_ATTRIBUTE_WALK;
345 export_devices(udev);
351 export_prefix = optarg;
354 printf("%s\n", VERSION);
357 printf("Usage: udevadm info OPTIONS\n"
358 " --query=<type> query device information:\n"
359 " name name of device node\n"
360 " symlink pointing to node\n"
361 " path sys device path\n"
362 " property the device properties\n"
364 " --path=<syspath> sys device path used for query or attribute walk\n"
365 " --name=<name> node or symlink name used for query or attribute walk\n"
366 " --root prepend dev directory to path names\n"
367 " --attribute-walk print all key matches while walking along the chain\n"
368 " of parent devices\n"
369 " --device-id-of-file=<file> print major:minor of device containing this file\n"
370 " --export-db export the content of the udev database\n"
380 if (device == NULL) {
381 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
388 const char *node = udev_device_get_devnode(device);
391 fprintf(stderr, "no device node found\n");
397 printf("%s\n", udev_device_get_devnode(device));
399 size_t len = strlen(udev_get_dev_path(udev));
401 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
406 list_entry = udev_device_get_devlinks_list_entry(device);
407 while (list_entry != NULL) {
409 printf("%s", udev_list_entry_get_name(list_entry));
413 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
414 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
416 list_entry = udev_list_entry_get_next(list_entry);
417 if (list_entry != NULL)
423 printf("%s\n", udev_device_get_devpath(device));
426 list_entry = udev_device_get_properties_list_entry(device);
427 while (list_entry != NULL) {
428 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
429 list_entry = udev_list_entry_get_next(list_entry);
433 print_record(device);
436 fprintf(stderr, "unknown query type\n");
440 case ACTION_ATTRIBUTE_WALK:
441 if (device == NULL) {
442 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
446 print_device_chain(device);
448 case ACTION_DEVICE_ID_FILE:
449 if (stat_device(name, export, export_prefix) != 0)
453 printf("%s\n", udev_get_dev_path(udev));
456 fprintf(stderr, "missing option\n");
462 udev_device_unref(device);