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 static int convert_db(struct udev *udev)
205 struct udev_enumerate *udev_enumerate;
206 struct udev_list_entry *list_entry;
208 udev_enumerate = udev_enumerate_new(udev);
209 if (udev_enumerate == NULL)
211 udev_enumerate_scan_devices(udev_enumerate);
212 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
213 struct udev_device *device;
215 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
216 if (device != NULL) {
219 char to[UTIL_PATH_SIZE];
220 char devpath[UTIL_PATH_SIZE];
221 char from[UTIL_PATH_SIZE];
223 id = udev_device_get_id_filename(device);
225 udev_device_unref(device);
228 util_strscpyl(to, sizeof(to), udev_get_dev_path(udev), "/.udev/db/", id, NULL);
230 /* find old database with $subsys:$sysname */
231 util_strscpyl(from, sizeof(from), udev_get_dev_path(udev),
232 "/.udev/db/", udev_device_get_subsystem(device), ":",
233 udev_device_get_sysname(device), NULL);
234 if (lstat(from, &stats) == 0) {
235 if (lstat(to, &stats) == 0)
241 /* find old database with the encoded devpath */
242 util_path_encode(udev_device_get_devpath(device), devpath, sizeof(devpath));
243 util_strscpyl(from, sizeof(from), udev_get_dev_path(udev),
244 "/.udev/db/", devpath, NULL);
245 if (lstat(from, &stats) == 0) {
246 if (lstat(to, &stats) == 0)
252 /* read the old database, and write out a new one */
253 udev_device_read_db(device);
254 udev_device_update_db(device);
256 udev_device_unref(device);
259 udev_enumerate_unref(udev_enumerate);
263 int udevadm_info(struct udev *udev, int argc, char *argv[])
265 struct udev_device *device = NULL;
268 const char *export_prefix = NULL;
269 char path[UTIL_PATH_SIZE];
270 char name[UTIL_PATH_SIZE];
271 struct udev_list_entry *list_entry;
274 static const struct option options[] = {
275 { "name", required_argument, NULL, 'n' },
276 { "path", required_argument, NULL, 'p' },
277 { "query", required_argument, NULL, 'q' },
278 { "attribute-walk", no_argument, NULL, 'a' },
279 { "export-db", no_argument, NULL, 'e' },
280 { "convert-db", no_argument, NULL, 'C' },
281 { "root", no_argument, NULL, 'r' },
282 { "device-id-of-file", required_argument, NULL, 'd' },
283 { "export", no_argument, NULL, 'x' },
284 { "export-prefix", required_argument, NULL, 'P' },
285 { "version", no_argument, NULL, 'V' },
286 { "help", no_argument, NULL, 'h' },
293 ACTION_ATTRIBUTE_WALK,
295 ACTION_DEVICE_ID_FILE,
296 } action = ACTION_NONE;
305 } query = QUERY_NONE;
311 option = getopt_long(argc, argv, "aed:n:p:q:rxP:Vh", options, NULL);
315 dbg(udev, "option '%c'\n", option);
318 if (device != NULL) {
319 fprintf(stderr, "device already specified\n");
323 /* remove /dev if given */
324 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0)
325 util_strscpyl(name, sizeof(name), udev_get_dev_path(udev), "/", optarg, NULL);
327 util_strscpy(name, sizeof(name), optarg);
328 util_remove_trailing_chars(name, '/');
329 if (stat(name, &statbuf) < 0) {
330 fprintf(stderr, "device node not found\n");
336 if (S_ISBLK(statbuf.st_mode)) {
338 } else if (S_ISCHR(statbuf.st_mode)) {
341 fprintf(stderr, "device node has wrong file type\n");
345 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
346 if (device == NULL) {
347 fprintf(stderr, "device node not found\n");
354 if (device != NULL) {
355 fprintf(stderr, "device already specified\n");
359 /* add sys dir if needed */
360 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
361 util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), optarg, NULL);
363 util_strscpy(path, sizeof(path), optarg);
364 util_remove_trailing_chars(path, '/');
365 device = udev_device_new_from_syspath(udev, path);
366 if (device == NULL) {
367 fprintf(stderr, "device path not found\n");
373 action = ACTION_QUERY;
374 if (strcmp(optarg, "property") == 0 || strcmp(optarg, "env") == 0) {
375 query = QUERY_PROPERTY;
376 } else if (strcmp(optarg, "name") == 0) {
378 } else if (strcmp(optarg, "symlink") == 0) {
379 query = QUERY_SYMLINK;
380 } else if (strcmp(optarg, "path") == 0) {
382 } else if (strcmp(optarg, "all") == 0) {
385 fprintf(stderr, "unknown query type\n");
391 if (action == ACTION_NONE)
392 action = ACTION_ROOT;
396 action = ACTION_DEVICE_ID_FILE;
397 util_strscpy(name, sizeof(name), optarg);
400 action = ACTION_ATTRIBUTE_WALK;
403 export_devices(udev);
412 export_prefix = optarg;
415 printf("%s\n", VERSION);
418 printf("Usage: udevadm info OPTIONS\n"
419 " --query=<type> query device information:\n"
420 " name name of device node\n"
421 " symlink pointing to node\n"
422 " path sys device path\n"
423 " property the device properties\n"
425 " --path=<syspath> sys device path used for query or attribute walk\n"
426 " --name=<name> node or symlink name used for query or attribute walk\n"
427 " --root prepend dev directory to path names\n"
428 " --attribute-walk print all key matches while walking along the chain\n"
429 " of parent devices\n"
430 " --device-id-of-file=<file> print major:minor of device containing this file\n"
431 " --export export key/value pairs\n"
432 " --export-prefix export the key name with a prefix\n"
433 " --export-db export the content of the udev database\n"
434 " --convert-db convert older version of database without a reboot\n"
444 if (device == NULL) {
445 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
452 const char *node = udev_device_get_devnode(device);
455 fprintf(stderr, "no device node found\n");
461 printf("%s\n", udev_device_get_devnode(device));
463 size_t len = strlen(udev_get_dev_path(udev));
465 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
470 list_entry = udev_device_get_devlinks_list_entry(device);
471 while (list_entry != NULL) {
473 printf("%s", udev_list_entry_get_name(list_entry));
477 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
478 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
480 list_entry = udev_list_entry_get_next(list_entry);
481 if (list_entry != NULL)
487 printf("%s\n", udev_device_get_devpath(device));
490 list_entry = udev_device_get_properties_list_entry(device);
491 while (list_entry != NULL) {
493 const char *prefix = export_prefix;
497 printf("%s%s='%s'\n", prefix,
498 udev_list_entry_get_name(list_entry),
499 udev_list_entry_get_value(list_entry));
501 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
503 list_entry = udev_list_entry_get_next(list_entry);
507 print_record(device);
510 fprintf(stderr, "unknown query type\n");
514 case ACTION_ATTRIBUTE_WALK:
515 if (device == NULL) {
516 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
520 print_device_chain(device);
522 case ACTION_DEVICE_ID_FILE:
523 if (stat_device(name, export, export_prefix) != 0)
527 printf("%s\n", udev_get_dev_path(udev));
530 fprintf(stderr, "missing option\n");
536 udev_device_unref(device);