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, bool 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 static int convert_db(struct udev *udev)
200 struct udev_enumerate *udev_enumerate;
201 struct udev_list_entry *list_entry;
203 udev_enumerate = udev_enumerate_new(udev);
204 if (udev_enumerate == NULL)
206 udev_enumerate_scan_devices(udev_enumerate);
207 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
208 struct udev_device *device;
210 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
211 if (device != NULL) {
214 char to[UTIL_PATH_SIZE];
215 char devpath[UTIL_PATH_SIZE];
216 char from[UTIL_PATH_SIZE];
218 id = udev_device_get_id_filename(device);
220 udev_device_unref(device);
223 util_strscpyl(to, sizeof(to), udev_get_dev_path(udev), "/.udev/db/", id, NULL);
225 /* find old database with $subsys:$sysname */
226 util_strscpyl(from, sizeof(from), udev_get_dev_path(udev),
227 "/.udev/db/", udev_device_get_subsystem(device), ":",
228 udev_device_get_sysname(device), NULL);
229 if (lstat(from, &stats) == 0) {
230 if (lstat(to, &stats) == 0)
236 /* find old database with the encoded devpath */
237 util_path_encode(udev_device_get_devpath(device), devpath, sizeof(devpath));
238 util_strscpyl(from, sizeof(from), udev_get_dev_path(udev),
239 "/.udev/db/", devpath, NULL);
240 if (lstat(from, &stats) == 0) {
241 if (lstat(to, &stats) == 0)
247 /* read the old database, and write out a new one */
248 udev_device_read_db(device);
249 udev_device_update_db(device);
251 udev_device_unref(device);
254 udev_enumerate_unref(udev_enumerate);
258 int udevadm_info(struct udev *udev, int argc, char *argv[])
260 struct udev_device *device = NULL;
263 const char *export_prefix = NULL;
264 char path[UTIL_PATH_SIZE];
265 char name[UTIL_PATH_SIZE];
266 struct udev_list_entry *list_entry;
269 static const struct option options[] = {
270 { "name", required_argument, NULL, 'n' },
271 { "path", required_argument, NULL, 'p' },
272 { "query", required_argument, NULL, 'q' },
273 { "attribute-walk", no_argument, NULL, 'a' },
274 { "export-db", no_argument, NULL, 'e' },
275 { "convert-db", no_argument, NULL, 'C' },
276 { "root", no_argument, NULL, 'r' },
277 { "device-id-of-file", required_argument, NULL, 'd' },
278 { "export", no_argument, NULL, 'x' },
279 { "export-prefix", required_argument, NULL, 'P' },
280 { "version", no_argument, NULL, 'V' },
281 { "help", no_argument, NULL, 'h' },
288 ACTION_ATTRIBUTE_WALK,
290 ACTION_DEVICE_ID_FILE,
291 } action = ACTION_NONE;
300 } query = QUERY_NONE;
306 option = getopt_long(argc, argv, "aed:n:p:q:rxP:Vh", options, NULL);
310 dbg(udev, "option '%c'\n", option);
313 if (device != NULL) {
314 fprintf(stderr, "device already specified\n");
318 /* remove /dev if given */
319 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0)
320 util_strscpyl(name, sizeof(name), udev_get_dev_path(udev), "/", optarg, NULL);
322 util_strscpy(name, sizeof(name), optarg);
323 util_remove_trailing_chars(name, '/');
324 if (stat(name, &statbuf) < 0) {
325 fprintf(stderr, "device node not found\n");
331 if (S_ISBLK(statbuf.st_mode)) {
333 } else if (S_ISCHR(statbuf.st_mode)) {
336 fprintf(stderr, "device node has wrong file type\n");
340 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
341 if (device == NULL) {
342 fprintf(stderr, "device node not found\n");
349 if (device != NULL) {
350 fprintf(stderr, "device already specified\n");
354 /* add sys dir if needed */
355 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
356 util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), optarg, NULL);
358 util_strscpy(path, sizeof(path), optarg);
359 util_remove_trailing_chars(path, '/');
360 device = udev_device_new_from_syspath(udev, path);
361 if (device == NULL) {
362 fprintf(stderr, "device path not found\n");
368 action = ACTION_QUERY;
369 if (strcmp(optarg, "property") == 0 || strcmp(optarg, "env") == 0) {
370 query = QUERY_PROPERTY;
371 } else if (strcmp(optarg, "name") == 0) {
373 } else if (strcmp(optarg, "symlink") == 0) {
374 query = QUERY_SYMLINK;
375 } else if (strcmp(optarg, "path") == 0) {
377 } else if (strcmp(optarg, "all") == 0) {
380 fprintf(stderr, "unknown query type\n");
386 if (action == ACTION_NONE)
387 action = ACTION_ROOT;
391 action = ACTION_DEVICE_ID_FILE;
392 util_strscpy(name, sizeof(name), optarg);
395 action = ACTION_ATTRIBUTE_WALK;
398 export_devices(udev);
407 export_prefix = optarg;
410 printf("%s\n", VERSION);
413 printf("Usage: udevadm info OPTIONS\n"
414 " --query=<type> query device information:\n"
415 " name name of device node\n"
416 " symlink pointing to node\n"
417 " path sys device path\n"
418 " property the device properties\n"
420 " --path=<syspath> sys device path used for query or attribute walk\n"
421 " --name=<name> node or symlink name used for query or attribute walk\n"
422 " --root prepend dev directory to path names\n"
423 " --attribute-walk print all key matches while walking along the chain\n"
424 " of parent devices\n"
425 " --device-id-of-file=<file> print major:minor of device containing this file\n"
426 " --export export key/value pairs\n"
427 " --export-prefix export the key name with a prefix\n"
428 " --export-db export the content of the udev database\n"
429 " --convert-db convert older version of database without a reboot\n"
439 if (device == NULL) {
440 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
447 const char *node = udev_device_get_devnode(device);
450 fprintf(stderr, "no device node found\n");
456 printf("%s\n", udev_device_get_devnode(device));
458 size_t len = strlen(udev_get_dev_path(udev));
460 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
465 list_entry = udev_device_get_devlinks_list_entry(device);
466 while (list_entry != NULL) {
468 printf("%s", udev_list_entry_get_name(list_entry));
472 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
473 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
475 list_entry = udev_list_entry_get_next(list_entry);
476 if (list_entry != NULL)
482 printf("%s\n", udev_device_get_devpath(device));
485 list_entry = udev_device_get_properties_list_entry(device);
486 while (list_entry != NULL) {
488 const char *prefix = export_prefix;
492 printf("%s%s='%s'\n", prefix,
493 udev_list_entry_get_name(list_entry),
494 udev_list_entry_get_value(list_entry));
496 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
498 list_entry = udev_list_entry_get_next(list_entry);
502 print_record(device);
505 fprintf(stderr, "unknown query type\n");
509 case ACTION_ATTRIBUTE_WALK:
510 if (device == NULL) {
511 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
515 print_device_chain(device);
517 case ACTION_DEVICE_ID_FILE:
518 if (stat_device(name, export, export_prefix) != 0)
522 printf("%s\n", udev_get_dev_path(udev));
525 fprintf(stderr, "missing option\n");
531 udev_device_unref(device);