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;
95 struct udev_device *device_parent;
98 device = udev_device_new_from_devpath(udev, devpath);
103 "Udevinfo starts with the device specified by the devpath and then\n"
104 "walks up the chain of parent devices. It prints for every device\n"
105 "found, all possible attributes in the udev rules key format.\n"
106 "A rule to match, can be composed by the attributes of the device\n"
107 "and the attributes from one single parent device.\n"
110 printf(" looking at device '%s':\n", udev_device_get_devpath(device));
111 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device));
112 str = udev_device_get_subsystem(device);
115 printf(" SUBSYSTEM==\"%s\"\n", str);
116 str = udev_device_get_driver(device);
119 printf(" DRIVER==\"%s\"\n", str);
120 print_all_attributes(udev, udev_device_get_devpath(device), "ATTR");
122 device_parent = device;
124 device_parent = udev_device_get_parent(device_parent);
125 if (device_parent == NULL)
127 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent));
128 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent));
129 str = udev_device_get_subsystem(device_parent);
132 printf(" SUBSYSTEMS==\"%s\"\n", str);
133 str = udev_device_get_driver(device_parent);
136 printf(" DRIVERS==\"%s\"\n", str);
137 print_all_attributes(udev, udev_device_get_devpath(device_parent), "ATTRS");
138 } while (device_parent != NULL);
140 udev_device_unref(device);
144 static void print_record(struct udevice *udevice)
146 struct name_entry *name_loop;
148 printf("P: %s\n", udevice->dev->devpath);
149 printf("N: %s\n", udevice->name);
150 list_for_each_entry(name_loop, &udevice->symlink_list, node)
151 printf("S: %s\n", name_loop->name);
152 if (udevice->link_priority != 0)
153 printf("L: %i\n", udevice->link_priority);
154 if (udevice->partitions != 0)
155 printf("A:%u\n", udevice->partitions);
156 if (udevice->ignore_remove)
157 printf("R:%u\n", udevice->ignore_remove);
158 list_for_each_entry(name_loop, &udevice->env_list, node)
159 printf("E: %s\n", name_loop->name);
162 static void export_db(struct udev *udev)
164 LIST_HEAD(name_list);
165 struct name_entry *name_loop;
167 udev_db_get_all_entries(udev, &name_list);
168 list_for_each_entry(name_loop, &name_list, node) {
169 struct udevice *udevice_db;
171 udevice_db = udev_device_init(udev);
172 if (udevice_db == NULL)
174 if (udev_db_get_device(udevice_db, name_loop->name) == 0)
175 print_record(udevice_db);
177 udev_device_cleanup(udevice_db);
179 name_list_cleanup(udev, &name_list);
182 static int lookup_device_by_name(struct udev *udev, struct udevice **udevice, const char *name)
184 LIST_HEAD(name_list);
186 struct name_entry *device;
189 count = udev_db_get_devices_by_name(udev, name, &name_list);
193 info(udev, "found %i devices for '%s'\n", count, name);
195 /* select the device that seems to match */
196 list_for_each_entry(device, &name_list, node) {
197 struct udevice *udevice_loop;
198 char filename[UTIL_PATH_SIZE];
201 udevice_loop = udev_device_init(udev);
202 if (udevice_loop == NULL)
204 if (udev_db_get_device(udevice_loop, device->name) != 0)
206 info(udev, "found db entry '%s'\n", device->name);
208 /* make sure, we don't get a link of a different device */
209 util_strlcpy(filename, udev_get_dev_path(udev), sizeof(filename));
210 util_strlcat(filename, "/", sizeof(filename));
211 util_strlcat(filename, name, sizeof(filename));
212 if (stat(filename, &statbuf) != 0)
214 if (major(udevice_loop->devt) > 0 && udevice_loop->devt != statbuf.st_rdev) {
215 info(udev, "skip '%s', dev_t doesn't match\n", udevice_loop->name);
219 *udevice = udevice_loop;
222 udev_device_cleanup(udevice_loop);
225 name_list_cleanup(udev, &name_list);
229 static int stat_device(const char *name, int export, const char *prefix)
233 if (stat(name, &statbuf) != 0)
239 printf("%sMAJOR=%d\n"
241 prefix, major(statbuf.st_dev),
242 prefix, minor(statbuf.st_dev));
244 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
248 int udevadm_info(struct udev *udev, int argc, char *argv[])
250 struct udevice *udevice = NULL;
253 const char *export_prefix = NULL;
255 static const struct option options[] = {
256 { "name", 1, NULL, 'n' },
257 { "path", 1, NULL, 'p' },
258 { "query", 1, NULL, 'q' },
259 { "attribute-walk", 0, NULL, 'a' },
260 { "export-db", 0, NULL, 'e' },
261 { "root", 0, NULL, 'r' },
262 { "device-id-of-file", 1, NULL, 'd' },
263 { "export", 0, NULL, 'x' },
264 { "export-prefix", 1, NULL, 'P' },
265 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
266 { "help", 0, NULL, 'h' },
273 ACTION_ATTRIBUTE_WALK,
275 ACTION_DEVICE_ID_FILE,
276 } action = ACTION_NONE;
285 } query = QUERY_NONE;
287 char path[UTIL_PATH_SIZE] = "";
288 char name[UTIL_PATH_SIZE] = "";
289 struct name_entry *name_loop;
295 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
299 dbg(udev, "option '%c'\n", option);
302 /* remove /dev if given */
303 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) == 0)
304 util_strlcpy(name, &optarg[strlen(udev_get_dev_path(udev))+1], sizeof(name));
306 util_strlcpy(name, optarg, sizeof(name));
307 util_remove_trailing_chars(name, '/');
308 dbg(udev, "name: %s\n", name);
311 /* remove /sys if given */
312 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) == 0)
313 util_strlcpy(path, &optarg[strlen(udev_get_sys_path(udev))], sizeof(path));
315 util_strlcpy(path, optarg, sizeof(path));
316 util_remove_trailing_chars(path, '/');
318 /* possibly resolve to real devpath */
319 if (util_resolve_sys_link(udev, path, sizeof(path)) != 0) {
320 char temp[UTIL_PATH_SIZE];
323 /* also check if the parent is a link */
324 util_strlcpy(temp, path, sizeof(temp));
325 pos = strrchr(temp, '/');
327 char tail[UTIL_PATH_SIZE];
329 util_strlcpy(tail, pos, sizeof(tail));
331 if (util_resolve_sys_link(udev, temp, sizeof(temp)) == 0) {
332 util_strlcpy(path, temp, sizeof(path));
333 util_strlcat(path, tail, sizeof(path));
337 dbg(udev, "path: %s\n", path);
340 action = ACTION_QUERY;
341 if (strcmp(optarg, "name") == 0) {
345 if (strcmp(optarg, "symlink") == 0) {
346 query = QUERY_SYMLINK;
349 if (strcmp(optarg, "path") == 0) {
353 if (strcmp(optarg, "env") == 0) {
357 if (strcmp(optarg, "all") == 0) {
361 fprintf(stderr, "unknown query type\n");
365 if (action == ACTION_NONE)
366 action = ACTION_ROOT;
370 action = ACTION_DEVICE_ID_FILE;
371 util_strlcpy(name, optarg, sizeof(name));
374 action = ACTION_ATTRIBUTE_WALK;
383 export_prefix = optarg;
386 printf("%s\n", VERSION);
389 printf("udevinfo, version %s\n", VERSION);
392 printf("Usage: udevadm info OPTIONS\n"
393 " --query=<type> query database for the specified value:\n"
394 " name name of device node\n"
395 " symlink pointing to node\n"
396 " path sysfs device path\n"
397 " env the device related imported environment\n"
399 " --path=<devpath> sysfs device path used for query or chain\n"
400 " --name=<name> node or symlink name used for query\n"
401 " --root prepend to query result or print udev_root\n"
402 " --attribute-walk print all key matches while walking along chain\n"
403 " of parent devices\n"
404 " --device-id-of-file=<file> print major/minor of underlying device\n"
405 " --export-db export the content of the udev database\n"
406 " --help print this text\n"
417 /* needs devpath or node/symlink name for query */
418 if (path[0] != '\0') {
419 udevice = udev_device_init(udev);
420 if (udevice == NULL) {
424 if (udev_db_get_device(udevice, path) != 0) {
425 fprintf(stderr, "no record for '%s' in database\n", path);
429 } else if (name[0] != '\0') {
430 if (lookup_device_by_name(udev, &udevice, name) != 0) {
431 fprintf(stderr, "node name not found\n");
436 fprintf(stderr, "query needs --path or node --name specified\n");
444 printf("%s/%s\n", udev_get_dev_path(udev), udevice->name);
446 printf("%s\n", udevice->name);
449 list_for_each_entry(name_loop, &udevice->symlink_list, node) {
450 char c = name_loop->node.next != &udevice->symlink_list ? ' ' : '\n';
453 printf("%s/%s%c", udev_get_dev_path(udev), name_loop->name, c);
455 printf("%s%c", name_loop->name, c);
459 printf("%s\n", udevice->dev->devpath);
462 list_for_each_entry(name_loop, &udevice->env_list, node)
463 printf("%s\n", name_loop->name);
466 print_record(udevice);
469 fprintf(stderr, "unknown query type\n");
473 case ACTION_ATTRIBUTE_WALK:
474 if (path[0] != '\0') {
475 if (print_device_chain(udev, path) != 0) {
476 fprintf(stderr, "no valid sysfs device found\n");
480 } else if (name[0] != '\0') {
481 if (lookup_device_by_name(udev, &udevice, name) != 0) {
482 fprintf(stderr, "node name not found\n");
486 if (print_device_chain(udev, udevice->dev->devpath) != 0) {
487 fprintf(stderr, "no valid sysfs device found\n");
492 fprintf(stderr, "attribute walk needs --path or node --name specified\n");
497 case ACTION_DEVICE_ID_FILE:
498 if (stat_device(name, export, export_prefix) != 0)
502 printf("%s\n", udev_get_dev_path(udev));
505 fprintf(stderr, "missing option\n");
511 udev_device_cleanup(udevice);