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_list_entry *sysattr;
38 udev_list_entry_foreach(sysattr, udev_device_get_sysattr_list_entry(device)) {
44 if (0 == strcmp("s", udev_list_entry_get_value(sysattr)))
47 name = udev_list_entry_get_name(sysattr);
48 if (strcmp(name, "uevent") == 0)
50 if (strcmp(name, "dev") == 0)
53 value = udev_device_get_sysattr_value(device, name);
56 dbg(udev_device_get_udev(device), "attr '%s'='%s'\n", name, value);
58 /* skip nonprintable attributes */
60 while (len > 0 && isprint(value[len-1]))
63 dbg(udev_device_get_udev(device),
64 "attribute value of '%s' non-printable, skip\n", name);
68 printf(" %s{%s}==\"%s\"\n", key, name, value);
73 static int print_device_chain(struct udev_device *device)
75 struct udev_device *device_parent;
79 "Udevadm info starts with the device specified by the devpath and then\n"
80 "walks up the chain of parent devices. It prints for every device\n"
81 "found, all possible attributes in the udev rules key format.\n"
82 "A rule to match, can be composed by the attributes of the device\n"
83 "and the attributes from one single parent device.\n"
86 printf(" looking at device '%s':\n", udev_device_get_devpath(device));
87 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device));
88 str = udev_device_get_subsystem(device);
91 printf(" SUBSYSTEM==\"%s\"\n", str);
92 str = udev_device_get_driver(device);
95 printf(" DRIVER==\"%s\"\n", str);
96 print_all_attributes(device, "ATTR");
98 device_parent = device;
100 device_parent = udev_device_get_parent(device_parent);
101 if (device_parent == NULL)
103 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent));
104 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent));
105 str = udev_device_get_subsystem(device_parent);
108 printf(" SUBSYSTEMS==\"%s\"\n", str);
109 str = udev_device_get_driver(device_parent);
112 printf(" DRIVERS==\"%s\"\n", str);
113 print_all_attributes(device_parent, "ATTRS");
114 } while (device_parent != NULL);
119 static void print_record(struct udev_device *device)
124 struct udev_list_entry *list_entry;
126 printf("P: %s\n", udev_device_get_devpath(device));
128 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
129 str = udev_device_get_devnode(device);
131 printf("N: %s\n", &str[len+1]);
133 i = udev_device_get_devlink_priority(device);
135 printf("L: %i\n", i);
137 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
138 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
139 printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
142 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
144 udev_list_entry_get_name(list_entry),
145 udev_list_entry_get_value(list_entry));
149 static int stat_device(const char *name, bool export, const char *prefix)
153 if (stat(name, &statbuf) != 0)
159 printf("%sMAJOR=%d\n"
161 prefix, major(statbuf.st_dev),
162 prefix, minor(statbuf.st_dev));
164 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
168 static int export_devices(struct udev *udev)
170 struct udev_enumerate *udev_enumerate;
171 struct udev_list_entry *list_entry;
173 udev_enumerate = udev_enumerate_new(udev);
174 if (udev_enumerate == NULL)
176 udev_enumerate_scan_devices(udev_enumerate);
177 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
178 struct udev_device *device;
180 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
181 if (device != NULL) {
182 print_record(device);
183 udev_device_unref(device);
186 udev_enumerate_unref(udev_enumerate);
190 static int convert_db(struct udev *udev)
192 struct udev_enumerate *udev_enumerate;
193 struct udev_list_entry *list_entry;
195 udev_enumerate = udev_enumerate_new(udev);
196 if (udev_enumerate == NULL)
198 udev_enumerate_scan_devices(udev_enumerate);
199 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
200 struct udev_device *device;
202 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
203 if (device != NULL) {
206 char to[UTIL_PATH_SIZE];
207 char devpath[UTIL_PATH_SIZE];
208 char from[UTIL_PATH_SIZE];
210 id = udev_device_get_id_filename(device);
212 udev_device_unref(device);
215 util_strscpyl(to, sizeof(to), udev_get_dev_path(udev), "/.udev/db/", id, NULL);
217 /* find old database with $subsys:$sysname */
218 util_strscpyl(from, sizeof(from), udev_get_dev_path(udev),
219 "/.udev/db/", udev_device_get_subsystem(device), ":",
220 udev_device_get_sysname(device), NULL);
221 if (lstat(from, &stats) == 0) {
222 if (lstat(to, &stats) == 0)
228 /* find old database with the encoded devpath */
229 util_path_encode(udev_device_get_devpath(device), devpath, sizeof(devpath));
230 util_strscpyl(from, sizeof(from), udev_get_dev_path(udev),
231 "/.udev/db/", devpath, NULL);
232 if (lstat(from, &stats) == 0) {
233 if (lstat(to, &stats) == 0)
239 /* read the old database, and write out a new one */
240 udev_device_read_db(device);
241 udev_device_update_db(device);
243 udev_device_unref(device);
246 udev_enumerate_unref(udev_enumerate);
250 int udevadm_info(struct udev *udev, int argc, char *argv[])
252 struct udev_device *device = NULL;
255 const char *export_prefix = NULL;
256 char path[UTIL_PATH_SIZE];
257 char name[UTIL_PATH_SIZE];
258 struct udev_list_entry *list_entry;
261 static const struct option options[] = {
262 { "name", required_argument, NULL, 'n' },
263 { "path", required_argument, NULL, 'p' },
264 { "query", required_argument, NULL, 'q' },
265 { "attribute-walk", no_argument, NULL, 'a' },
266 { "export-db", no_argument, NULL, 'e' },
267 { "convert-db", no_argument, NULL, 'C' },
268 { "root", no_argument, NULL, 'r' },
269 { "device-id-of-file", required_argument, NULL, 'd' },
270 { "export", no_argument, NULL, 'x' },
271 { "export-prefix", required_argument, NULL, 'P' },
272 { "version", no_argument, NULL, 'V' },
273 { "help", no_argument, NULL, 'h' },
280 ACTION_ATTRIBUTE_WALK,
282 ACTION_DEVICE_ID_FILE,
283 } action = ACTION_NONE;
292 } query = QUERY_NONE;
298 option = getopt_long(argc, argv, "aed:n:p:q:rxP:Vh", options, NULL);
302 dbg(udev, "option '%c'\n", option);
305 if (device != NULL) {
306 fprintf(stderr, "device already specified\n");
310 /* remove /dev if given */
311 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0)
312 util_strscpyl(name, sizeof(name), udev_get_dev_path(udev), "/", optarg, NULL);
314 util_strscpy(name, sizeof(name), optarg);
315 util_remove_trailing_chars(name, '/');
316 if (stat(name, &statbuf) < 0) {
317 fprintf(stderr, "device node not found\n");
323 if (S_ISBLK(statbuf.st_mode)) {
325 } else if (S_ISCHR(statbuf.st_mode)) {
328 fprintf(stderr, "device node has wrong file type\n");
332 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
333 if (device == NULL) {
334 fprintf(stderr, "device node not found\n");
341 if (device != NULL) {
342 fprintf(stderr, "device already specified\n");
346 /* add sys dir if needed */
347 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
348 util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), optarg, NULL);
350 util_strscpy(path, sizeof(path), optarg);
351 util_remove_trailing_chars(path, '/');
352 device = udev_device_new_from_syspath(udev, path);
353 if (device == NULL) {
354 fprintf(stderr, "device path not found\n");
360 action = ACTION_QUERY;
361 if (strcmp(optarg, "property") == 0 || strcmp(optarg, "env") == 0) {
362 query = QUERY_PROPERTY;
363 } else if (strcmp(optarg, "name") == 0) {
365 } else if (strcmp(optarg, "symlink") == 0) {
366 query = QUERY_SYMLINK;
367 } else if (strcmp(optarg, "path") == 0) {
369 } else if (strcmp(optarg, "all") == 0) {
372 fprintf(stderr, "unknown query type\n");
378 if (action == ACTION_NONE)
379 action = ACTION_ROOT;
383 action = ACTION_DEVICE_ID_FILE;
384 util_strscpy(name, sizeof(name), optarg);
387 action = ACTION_ATTRIBUTE_WALK;
390 export_devices(udev);
399 export_prefix = optarg;
402 printf("%s\n", VERSION);
405 printf("Usage: udevadm info OPTIONS\n"
406 " --query=<type> query device information:\n"
407 " name name of device node\n"
408 " symlink pointing to node\n"
409 " path sys device path\n"
410 " property the device properties\n"
412 " --path=<syspath> sys device path used for query or attribute walk\n"
413 " --name=<name> node or symlink name used for query or attribute walk\n"
414 " --root prepend dev directory to path names\n"
415 " --attribute-walk print all key matches while walking along the chain\n"
416 " of parent devices\n"
417 " --device-id-of-file=<file> print major:minor of device containing this file\n"
418 " --export export key/value pairs\n"
419 " --export-prefix export the key name with a prefix\n"
420 " --export-db export the content of the udev database\n"
421 " --convert-db convert older version of database without a reboot\n"
431 if (device == NULL) {
432 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
439 const char *node = udev_device_get_devnode(device);
442 fprintf(stderr, "no device node found\n");
448 printf("%s\n", udev_device_get_devnode(device));
450 size_t len = strlen(udev_get_dev_path(udev));
452 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
457 list_entry = udev_device_get_devlinks_list_entry(device);
458 while (list_entry != NULL) {
460 printf("%s", udev_list_entry_get_name(list_entry));
464 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
465 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
467 list_entry = udev_list_entry_get_next(list_entry);
468 if (list_entry != NULL)
474 printf("%s\n", udev_device_get_devpath(device));
477 list_entry = udev_device_get_properties_list_entry(device);
478 while (list_entry != NULL) {
480 const char *prefix = export_prefix;
484 printf("%s%s='%s'\n", prefix,
485 udev_list_entry_get_name(list_entry),
486 udev_list_entry_get_value(list_entry));
488 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
490 list_entry = udev_list_entry_get_next(list_entry);
494 print_record(device);
497 fprintf(stderr, "unknown query type\n");
501 case ACTION_ATTRIBUTE_WALK:
502 if (device == NULL) {
503 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
507 print_device_chain(device);
509 case ACTION_DEVICE_ID_FILE:
510 if (stat_device(name, export, export_prefix) != 0)
514 printf("%s\n", udev_get_dev_path(udev));
517 fprintf(stderr, "missing option\n");
523 udev_device_unref(device);