2 * Copyright (C) 2004-2006 Kay Sievers <kay.sievers@vrfy.org>
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation version 2 of the License.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
32 #include <sys/types.h>
36 static void print_all_attributes(struct udev *udev, const char *devpath, const char *key)
42 strlcpy(path, udev_get_sys_path(udev), sizeof(path));
43 strlcat(path, devpath, sizeof(path));
47 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
49 char filename[PATH_SIZE];
51 char value[NAME_SIZE];
54 if (dent->d_name[0] == '.')
57 if (strcmp(dent->d_name, "uevent") == 0)
59 if (strcmp(dent->d_name, "dev") == 0)
62 strlcpy(filename, path, sizeof(filename));
63 strlcat(filename, "/", sizeof(filename));
64 strlcat(filename, dent->d_name, sizeof(filename));
65 if (lstat(filename, &statbuf) != 0)
67 if (S_ISLNK(statbuf.st_mode))
70 attr_value = sysfs_attr_get_value(udev, devpath, dent->d_name);
71 if (attr_value == NULL)
73 len = strlcpy(value, attr_value, sizeof(value));
74 if(len >= sizeof(value))
75 len = sizeof(value) - 1;
76 dbg(udev, "attr '%s'='%s'(%zi)\n", dent->d_name, value, len);
78 /* skip nonprintable attributes */
79 while (len && isprint(value[len-1]))
82 dbg(udev, "attribute value of '%s' non-printable, skip\n", dent->d_name);
86 printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
92 static int print_device_chain(struct udev *udev, const char *devpath)
94 struct sysfs_device *dev;
96 dev = sysfs_device_get(udev, devpath);
101 "Udevinfo starts with the device specified by the devpath and then\n"
102 "walks up the chain of parent devices. It prints for every device\n"
103 "found, all possible attributes in the udev rules key format.\n"
104 "A rule to match, can be composed by the attributes of the device\n"
105 "and the attributes from one single parent device.\n"
108 printf(" looking at device '%s':\n", dev->devpath);
109 printf(" KERNEL==\"%s\"\n", dev->kernel);
110 printf(" SUBSYSTEM==\"%s\"\n", dev->subsystem);
111 printf(" DRIVER==\"%s\"\n", dev->driver);
112 print_all_attributes(udev, dev->devpath, "ATTR");
114 /* walk up the chain of devices */
116 dev = sysfs_device_get_parent(udev, dev);
119 printf(" looking at parent device '%s':\n", dev->devpath);
120 printf(" KERNELS==\"%s\"\n", dev->kernel);
121 printf(" SUBSYSTEMS==\"%s\"\n", dev->subsystem);
122 printf(" DRIVERS==\"%s\"\n", dev->driver);
124 print_all_attributes(udev, dev->devpath, "ATTRS");
130 static void print_record(struct udevice *udevice)
132 struct name_entry *name_loop;
134 printf("P: %s\n", udevice->dev->devpath);
135 printf("N: %s\n", udevice->name);
136 list_for_each_entry(name_loop, &udevice->symlink_list, node)
137 printf("S: %s\n", name_loop->name);
138 if (udevice->link_priority != 0)
139 printf("L: %i\n", udevice->link_priority);
140 if (udevice->partitions != 0)
141 printf("A:%u\n", udevice->partitions);
142 if (udevice->ignore_remove)
143 printf("R:%u\n", udevice->ignore_remove);
144 list_for_each_entry(name_loop, &udevice->env_list, node)
145 printf("E: %s\n", name_loop->name);
148 static void export_db(struct udev *udev)
150 LIST_HEAD(name_list);
151 struct name_entry *name_loop;
153 udev_db_get_all_entries(udev, &name_list);
154 list_for_each_entry(name_loop, &name_list, node) {
155 struct udevice *udevice_db;
157 udevice_db = udev_device_init(udev);
158 if (udevice_db == NULL)
160 if (udev_db_get_device(udevice_db, name_loop->name) == 0)
161 print_record(udevice_db);
163 udev_device_cleanup(udevice_db);
165 name_list_cleanup(udev, &name_list);
168 static int lookup_device_by_name(struct udev *udev, struct udevice **udevice, const char *name)
170 LIST_HEAD(name_list);
172 struct name_entry *device;
175 count = udev_db_get_devices_by_name(udev, name, &name_list);
179 info(udev, "found %i devices for '%s'\n", count, name);
181 /* select the device that seems to match */
182 list_for_each_entry(device, &name_list, node) {
183 struct udevice *udevice_loop;
184 char filename[PATH_SIZE];
187 udevice_loop = udev_device_init(udev);
188 if (udevice_loop == NULL)
190 if (udev_db_get_device(udevice_loop, device->name) != 0)
192 info(udev, "found db entry '%s'\n", device->name);
194 /* make sure, we don't get a link of a different device */
195 strlcpy(filename, udev_get_dev_path(udev), sizeof(filename));
196 strlcat(filename, "/", sizeof(filename));
197 strlcat(filename, name, sizeof(filename));
198 if (stat(filename, &statbuf) != 0)
200 if (major(udevice_loop->devt) > 0 && udevice_loop->devt != statbuf.st_rdev) {
201 info(udev, "skip '%s', dev_t doesn't match\n", udevice_loop->name);
205 *udevice = udevice_loop;
208 udev_device_cleanup(udevice_loop);
211 name_list_cleanup(udev, &name_list);
215 static int stat_device(const char *name, int export, const char *prefix)
219 if (stat(name, &statbuf) != 0)
225 printf("%sMAJOR=%d\n"
227 prefix, major(statbuf.st_dev),
228 prefix, minor(statbuf.st_dev));
230 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
234 int udevadm_info(struct udev *udev, int argc, char *argv[])
236 struct udevice *udevice = NULL;
239 const char *export_prefix = NULL;
241 static const struct option options[] = {
242 { "name", 1, NULL, 'n' },
243 { "path", 1, NULL, 'p' },
244 { "query", 1, NULL, 'q' },
245 { "attribute-walk", 0, NULL, 'a' },
246 { "export-db", 0, NULL, 'e' },
247 { "root", 0, NULL, 'r' },
248 { "device-id-of-file", 1, NULL, 'd' },
249 { "export", 0, NULL, 'x' },
250 { "export-prefix", 1, NULL, 'P' },
251 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
252 { "help", 0, NULL, 'h' },
259 ACTION_ATTRIBUTE_WALK,
261 ACTION_DEVICE_ID_FILE,
262 } action = ACTION_NONE;
271 } query = QUERY_NONE;
273 char path[PATH_SIZE] = "";
274 char name[PATH_SIZE] = "";
275 struct name_entry *name_loop;
281 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
285 dbg(udev, "option '%c'\n", option);
288 /* remove /dev if given */
289 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) == 0)
290 strlcpy(name, &optarg[strlen(udev_get_dev_path(udev))+1], sizeof(name));
292 strlcpy(name, optarg, sizeof(name));
293 remove_trailing_chars(name, '/');
294 dbg(udev, "name: %s\n", name);
297 /* remove /sys if given */
298 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) == 0)
299 strlcpy(path, &optarg[strlen(udev_get_sys_path(udev))], sizeof(path));
301 strlcpy(path, optarg, sizeof(path));
302 remove_trailing_chars(path, '/');
304 /* possibly resolve to real devpath */
305 if (sysfs_resolve_link(udev, path, sizeof(path)) != 0) {
306 char temp[PATH_SIZE];
309 /* also check if the parent is a link */
310 strlcpy(temp, path, sizeof(temp));
311 pos = strrchr(temp, '/');
313 char tail[PATH_SIZE];
315 strlcpy(tail, pos, sizeof(tail));
317 if (sysfs_resolve_link(udev, temp, sizeof(temp)) == 0) {
318 strlcpy(path, temp, sizeof(path));
319 strlcat(path, tail, sizeof(path));
323 dbg(udev, "path: %s\n", path);
326 action = ACTION_QUERY;
327 if (strcmp(optarg, "name") == 0) {
331 if (strcmp(optarg, "symlink") == 0) {
332 query = QUERY_SYMLINK;
335 if (strcmp(optarg, "path") == 0) {
339 if (strcmp(optarg, "env") == 0) {
343 if (strcmp(optarg, "all") == 0) {
347 fprintf(stderr, "unknown query type\n");
351 if (action == ACTION_NONE)
352 action = ACTION_ROOT;
356 action = ACTION_DEVICE_ID_FILE;
357 strlcpy(name, optarg, sizeof(name));
360 action = ACTION_ATTRIBUTE_WALK;
369 export_prefix = optarg;
372 printf("%s\n", VERSION);
375 printf("udevinfo, version %s\n", VERSION);
378 printf("Usage: udevadm info OPTIONS\n"
379 " --query=<type> query database for the specified value:\n"
380 " name name of device node\n"
381 " symlink pointing to node\n"
382 " path sysfs device path\n"
383 " env the device related imported environment\n"
385 " --path=<devpath> sysfs device path used for query or chain\n"
386 " --name=<name> node or symlink name used for query\n"
387 " --root prepend to query result or print udev_root\n"
388 " --attribute-walk print all key matches while walking along chain\n"
389 " of parent devices\n"
390 " --device-id-of-file=<file> print major/minor of underlying device\n"
391 " --export-db export the content of the udev database\n"
392 " --help print this text\n"
403 /* needs devpath or node/symlink name for query */
404 if (path[0] != '\0') {
405 udevice = udev_device_init(udev);
406 if (udevice == NULL) {
410 if (udev_db_get_device(udevice, path) != 0) {
411 fprintf(stderr, "no record for '%s' in database\n", path);
415 } else if (name[0] != '\0') {
416 if (lookup_device_by_name(udev, &udevice, name) != 0) {
417 fprintf(stderr, "node name not found\n");
422 fprintf(stderr, "query needs --path or node --name specified\n");
430 printf("%s/%s\n", udev_get_dev_path(udev), udevice->name);
432 printf("%s\n", udevice->name);
435 list_for_each_entry(name_loop, &udevice->symlink_list, node) {
436 char c = name_loop->node.next != &udevice->symlink_list ? ' ' : '\n';
439 printf("%s/%s%c", udev_get_dev_path(udev), name_loop->name, c);
441 printf("%s%c", name_loop->name, c);
445 printf("%s\n", udevice->dev->devpath);
448 list_for_each_entry(name_loop, &udevice->env_list, node)
449 printf("%s\n", name_loop->name);
452 print_record(udevice);
455 fprintf(stderr, "unknown query type\n");
459 case ACTION_ATTRIBUTE_WALK:
460 if (path[0] != '\0') {
461 if (print_device_chain(udev, path) != 0) {
462 fprintf(stderr, "no valid sysfs device found\n");
466 } else if (name[0] != '\0') {
467 if (lookup_device_by_name(udev, &udevice, name) != 0) {
468 fprintf(stderr, "node name not found\n");
472 if (print_device_chain(udev, udevice->dev->devpath) != 0) {
473 fprintf(stderr, "no valid sysfs device found\n");
478 fprintf(stderr, "attribute walk needs --path or node --name specified\n");
483 case ACTION_DEVICE_ID_FILE:
484 if (stat_device(name, export, export_prefix) != 0)
488 printf("%s\n", udev_get_dev_path(udev));
491 fprintf(stderr, "missing option\n");
497 udev_device_cleanup(udevice);