2 * Copyright (C) 2004-2008 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/>.
31 #include <sys/types.h>
35 static void print_all_attributes(struct udev *udev, const char *devpath, const char *key)
37 char path[UTIL_PATH_SIZE];
41 util_strlcpy(path, udev_get_sys_path(udev), sizeof(path));
42 util_strlcat(path, devpath, sizeof(path));
46 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
48 char filename[UTIL_PATH_SIZE];
50 char value[UTIL_NAME_SIZE];
53 if (dent->d_name[0] == '.')
56 if (strcmp(dent->d_name, "uevent") == 0)
58 if (strcmp(dent->d_name, "dev") == 0)
61 util_strlcpy(filename, path, sizeof(filename));
62 util_strlcat(filename, "/", sizeof(filename));
63 util_strlcat(filename, dent->d_name, sizeof(filename));
64 if (lstat(filename, &statbuf) != 0)
66 if (S_ISLNK(statbuf.st_mode))
69 attr_value = sysfs_attr_get_value(udev, devpath, dent->d_name);
70 if (attr_value == NULL)
72 len = util_strlcpy(value, attr_value, sizeof(value));
73 if(len >= sizeof(value))
74 len = sizeof(value) - 1;
75 dbg(udev, "attr '%s'='%s'(%zi)\n", dent->d_name, value, len);
77 /* skip nonprintable attributes */
78 while (len && isprint(value[len-1]))
81 dbg(udev, "attribute value of '%s' non-printable, skip\n", dent->d_name);
85 printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
92 static int print_device_chain(struct udev *udev, const char *devpath)
94 struct udev_device *device;
97 device = udev_device_new_from_devpath(udev, devpath);
102 "Udevinfo starts with the device specified by the devpath and then\n"
103 "walks up the chain of parent devices. It prints for every device\n"
104 "found, all possible attributes in the udev rules key format.\n"
105 "A rule to match, can be composed by the attributes of the device\n"
106 "and the attributes from one single parent device.\n"
109 printf(" looking at device '%s':\n", udev_device_get_devpath(device));
110 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device));
111 str = udev_device_get_subsystem(device);
114 printf(" SUBSYSTEM==\"%s\"\n", str);
115 str = udev_device_get_driver(device);
118 printf(" DRIVER==\"%s\"\n", str);
119 print_all_attributes(udev, udev_device_get_devpath(device), "ATTR");
121 while (device != NULL) {
122 struct udev_device *device_parent;
124 device_parent = udev_device_new_from_parent(device);
125 udev_device_unref(device);
126 if (device_parent == NULL)
128 device = device_parent;
129 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device));
130 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device));
131 str = udev_device_get_subsystem(device);
134 printf(" SUBSYSTEMS==\"%s\"\n", str);
135 str = udev_device_get_driver(device);
138 printf(" DRIVERS==\"%s\"\n", str);
139 print_all_attributes(udev, udev_device_get_devpath(device), "ATTRS");
145 static void print_record(struct udevice *udevice)
147 struct name_entry *name_loop;
149 printf("P: %s\n", udevice->dev->devpath);
150 printf("N: %s\n", udevice->name);
151 list_for_each_entry(name_loop, &udevice->symlink_list, node)
152 printf("S: %s\n", name_loop->name);
153 if (udevice->link_priority != 0)
154 printf("L: %i\n", udevice->link_priority);
155 if (udevice->partitions != 0)
156 printf("A:%u\n", udevice->partitions);
157 if (udevice->ignore_remove)
158 printf("R:%u\n", udevice->ignore_remove);
159 list_for_each_entry(name_loop, &udevice->env_list, node)
160 printf("E: %s\n", name_loop->name);
163 static void export_db(struct udev *udev)
165 LIST_HEAD(name_list);
166 struct name_entry *name_loop;
168 udev_db_get_all_entries(udev, &name_list);
169 list_for_each_entry(name_loop, &name_list, node) {
170 struct udevice *udevice_db;
172 udevice_db = udev_device_init(udev);
173 if (udevice_db == NULL)
175 if (udev_db_get_device(udevice_db, name_loop->name) == 0)
176 print_record(udevice_db);
178 udev_device_cleanup(udevice_db);
180 name_list_cleanup(udev, &name_list);
183 static int lookup_device_by_name(struct udev *udev, struct udevice **udevice, const char *name)
185 LIST_HEAD(name_list);
187 struct name_entry *device;
190 count = udev_db_get_devices_by_name(udev, name, &name_list);
194 info(udev, "found %i devices for '%s'\n", count, name);
196 /* select the device that seems to match */
197 list_for_each_entry(device, &name_list, node) {
198 struct udevice *udevice_loop;
199 char filename[UTIL_PATH_SIZE];
202 udevice_loop = udev_device_init(udev);
203 if (udevice_loop == NULL)
205 if (udev_db_get_device(udevice_loop, device->name) != 0)
207 info(udev, "found db entry '%s'\n", device->name);
209 /* make sure, we don't get a link of a different device */
210 util_strlcpy(filename, udev_get_dev_path(udev), sizeof(filename));
211 util_strlcat(filename, "/", sizeof(filename));
212 util_strlcat(filename, name, sizeof(filename));
213 if (stat(filename, &statbuf) != 0)
215 if (major(udevice_loop->devt) > 0 && udevice_loop->devt != statbuf.st_rdev) {
216 info(udev, "skip '%s', dev_t doesn't match\n", udevice_loop->name);
220 *udevice = udevice_loop;
223 udev_device_cleanup(udevice_loop);
226 name_list_cleanup(udev, &name_list);
230 static int stat_device(const char *name, int export, const char *prefix)
234 if (stat(name, &statbuf) != 0)
240 printf("%sMAJOR=%d\n"
242 prefix, major(statbuf.st_dev),
243 prefix, minor(statbuf.st_dev));
245 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
249 int udevadm_info(struct udev *udev, int argc, char *argv[])
251 struct udevice *udevice = NULL;
254 const char *export_prefix = NULL;
256 static const struct option options[] = {
257 { "name", 1, NULL, 'n' },
258 { "path", 1, NULL, 'p' },
259 { "query", 1, NULL, 'q' },
260 { "attribute-walk", 0, NULL, 'a' },
261 { "export-db", 0, NULL, 'e' },
262 { "root", 0, NULL, 'r' },
263 { "device-id-of-file", 1, NULL, 'd' },
264 { "export", 0, NULL, 'x' },
265 { "export-prefix", 1, NULL, 'P' },
266 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
267 { "help", 0, NULL, 'h' },
274 ACTION_ATTRIBUTE_WALK,
276 ACTION_DEVICE_ID_FILE,
277 } action = ACTION_NONE;
286 } query = QUERY_NONE;
288 char path[UTIL_PATH_SIZE] = "";
289 char name[UTIL_PATH_SIZE] = "";
290 struct name_entry *name_loop;
296 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
300 dbg(udev, "option '%c'\n", option);
303 /* remove /dev if given */
304 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) == 0)
305 util_strlcpy(name, &optarg[strlen(udev_get_dev_path(udev))+1], sizeof(name));
307 util_strlcpy(name, optarg, sizeof(name));
308 util_remove_trailing_chars(name, '/');
309 dbg(udev, "name: %s\n", name);
312 /* remove /sys if given */
313 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) == 0)
314 util_strlcpy(path, &optarg[strlen(udev_get_sys_path(udev))], sizeof(path));
316 util_strlcpy(path, optarg, sizeof(path));
317 util_remove_trailing_chars(path, '/');
319 /* possibly resolve to real devpath */
320 if (util_resolve_sys_link(udev, path, sizeof(path)) != 0) {
321 char temp[UTIL_PATH_SIZE];
324 /* also check if the parent is a link */
325 util_strlcpy(temp, path, sizeof(temp));
326 pos = strrchr(temp, '/');
328 char tail[UTIL_PATH_SIZE];
330 util_strlcpy(tail, pos, sizeof(tail));
332 if (util_resolve_sys_link(udev, temp, sizeof(temp)) == 0) {
333 util_strlcpy(path, temp, sizeof(path));
334 util_strlcat(path, tail, sizeof(path));
338 dbg(udev, "path: %s\n", path);
341 action = ACTION_QUERY;
342 if (strcmp(optarg, "name") == 0) {
346 if (strcmp(optarg, "symlink") == 0) {
347 query = QUERY_SYMLINK;
350 if (strcmp(optarg, "path") == 0) {
354 if (strcmp(optarg, "env") == 0) {
358 if (strcmp(optarg, "all") == 0) {
362 fprintf(stderr, "unknown query type\n");
366 if (action == ACTION_NONE)
367 action = ACTION_ROOT;
371 action = ACTION_DEVICE_ID_FILE;
372 util_strlcpy(name, optarg, sizeof(name));
375 action = ACTION_ATTRIBUTE_WALK;
384 export_prefix = optarg;
387 printf("%s\n", VERSION);
390 printf("udevinfo, version %s\n", VERSION);
393 printf("Usage: udevadm info OPTIONS\n"
394 " --query=<type> query database for the specified value:\n"
395 " name name of device node\n"
396 " symlink pointing to node\n"
397 " path sysfs device path\n"
398 " env the device related imported environment\n"
400 " --path=<devpath> sysfs device path used for query or chain\n"
401 " --name=<name> node or symlink name used for query\n"
402 " --root prepend to query result or print udev_root\n"
403 " --attribute-walk print all key matches while walking along chain\n"
404 " of parent devices\n"
405 " --device-id-of-file=<file> print major/minor of underlying device\n"
406 " --export-db export the content of the udev database\n"
407 " --help print this text\n"
418 /* needs devpath or node/symlink name for query */
419 if (path[0] != '\0') {
420 udevice = udev_device_init(udev);
421 if (udevice == NULL) {
425 if (udev_db_get_device(udevice, path) != 0) {
426 fprintf(stderr, "no record for '%s' in database\n", path);
430 } else if (name[0] != '\0') {
431 if (lookup_device_by_name(udev, &udevice, name) != 0) {
432 fprintf(stderr, "node name not found\n");
437 fprintf(stderr, "query needs --path or node --name specified\n");
445 printf("%s/%s\n", udev_get_dev_path(udev), udevice->name);
447 printf("%s\n", udevice->name);
450 list_for_each_entry(name_loop, &udevice->symlink_list, node) {
451 char c = name_loop->node.next != &udevice->symlink_list ? ' ' : '\n';
454 printf("%s/%s%c", udev_get_dev_path(udev), name_loop->name, c);
456 printf("%s%c", name_loop->name, c);
460 printf("%s\n", udevice->dev->devpath);
463 list_for_each_entry(name_loop, &udevice->env_list, node)
464 printf("%s\n", name_loop->name);
467 print_record(udevice);
470 fprintf(stderr, "unknown query type\n");
474 case ACTION_ATTRIBUTE_WALK:
475 if (path[0] != '\0') {
476 if (print_device_chain(udev, path) != 0) {
477 fprintf(stderr, "no valid sysfs device found\n");
481 } else if (name[0] != '\0') {
482 if (lookup_device_by_name(udev, &udevice, name) != 0) {
483 fprintf(stderr, "node name not found\n");
487 if (print_device_chain(udev, udevice->dev->devpath) != 0) {
488 fprintf(stderr, "no valid sysfs device found\n");
493 fprintf(stderr, "attribute walk needs --path or node --name specified\n");
498 case ACTION_DEVICE_ID_FILE:
499 if (stat_device(name, export, export_prefix) != 0)
503 printf("%s\n", udev_get_dev_path(udev));
506 fprintf(stderr, "missing option\n");
512 udev_device_cleanup(udevice);