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)
41 strlcpy(path, udev_get_sys_path(udev), sizeof(path));
42 strlcat(path, devpath, sizeof(path));
46 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
48 char filename[PATH_SIZE];
50 char value[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 strlcpy(filename, path, sizeof(filename));
62 strlcat(filename, "/", sizeof(filename));
63 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 = 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);
91 static int print_device_chain(struct udev *udev, const char *devpath)
93 struct sysfs_device *dev;
95 dev = sysfs_device_get(udev, devpath);
100 "Udevinfo starts with the device specified by the devpath and then\n"
101 "walks up the chain of parent devices. It prints for every device\n"
102 "found, all possible attributes in the udev rules key format.\n"
103 "A rule to match, can be composed by the attributes of the device\n"
104 "and the attributes from one single parent device.\n"
107 printf(" looking at device '%s':\n", dev->devpath);
108 printf(" KERNEL==\"%s\"\n", dev->kernel);
109 printf(" SUBSYSTEM==\"%s\"\n", dev->subsystem);
110 printf(" DRIVER==\"%s\"\n", dev->driver);
111 print_all_attributes(udev, dev->devpath, "ATTR");
113 /* walk up the chain of devices */
115 dev = sysfs_device_get_parent(udev, dev);
118 printf(" looking at parent device '%s':\n", dev->devpath);
119 printf(" KERNELS==\"%s\"\n", dev->kernel);
120 printf(" SUBSYSTEMS==\"%s\"\n", dev->subsystem);
121 printf(" DRIVERS==\"%s\"\n", dev->driver);
123 print_all_attributes(udev, dev->devpath, "ATTRS");
129 static void print_record(struct udevice *udevice)
131 struct name_entry *name_loop;
133 printf("P: %s\n", udevice->dev->devpath);
134 printf("N: %s\n", udevice->name);
135 list_for_each_entry(name_loop, &udevice->symlink_list, node)
136 printf("S: %s\n", name_loop->name);
137 if (udevice->link_priority != 0)
138 printf("L: %i\n", udevice->link_priority);
139 if (udevice->partitions != 0)
140 printf("A:%u\n", udevice->partitions);
141 if (udevice->ignore_remove)
142 printf("R:%u\n", udevice->ignore_remove);
143 list_for_each_entry(name_loop, &udevice->env_list, node)
144 printf("E: %s\n", name_loop->name);
147 static void export_db(struct udev *udev)
149 LIST_HEAD(name_list);
150 struct name_entry *name_loop;
152 udev_db_get_all_entries(udev, &name_list);
153 list_for_each_entry(name_loop, &name_list, node) {
154 struct udevice *udevice_db;
156 udevice_db = udev_device_init(udev);
157 if (udevice_db == NULL)
159 if (udev_db_get_device(udevice_db, name_loop->name) == 0)
160 print_record(udevice_db);
162 udev_device_cleanup(udevice_db);
164 name_list_cleanup(udev, &name_list);
167 static int lookup_device_by_name(struct udev *udev, struct udevice **udevice, const char *name)
169 LIST_HEAD(name_list);
171 struct name_entry *device;
174 count = udev_db_get_devices_by_name(udev, name, &name_list);
178 info(udev, "found %i devices for '%s'\n", count, name);
180 /* select the device that seems to match */
181 list_for_each_entry(device, &name_list, node) {
182 struct udevice *udevice_loop;
183 char filename[PATH_SIZE];
186 udevice_loop = udev_device_init(udev);
187 if (udevice_loop == NULL)
189 if (udev_db_get_device(udevice_loop, device->name) != 0)
191 info(udev, "found db entry '%s'\n", device->name);
193 /* make sure, we don't get a link of a different device */
194 strlcpy(filename, udev_get_dev_path(udev), sizeof(filename));
195 strlcat(filename, "/", sizeof(filename));
196 strlcat(filename, name, sizeof(filename));
197 if (stat(filename, &statbuf) != 0)
199 if (major(udevice_loop->devt) > 0 && udevice_loop->devt != statbuf.st_rdev) {
200 info(udev, "skip '%s', dev_t doesn't match\n", udevice_loop->name);
204 *udevice = udevice_loop;
207 udev_device_cleanup(udevice_loop);
210 name_list_cleanup(udev, &name_list);
214 static int stat_device(const char *name, int export, const char *prefix)
218 if (stat(name, &statbuf) != 0)
224 printf("%sMAJOR=%d\n"
226 prefix, major(statbuf.st_dev),
227 prefix, minor(statbuf.st_dev));
229 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
233 int udevadm_info(struct udev *udev, int argc, char *argv[])
235 struct udevice *udevice = NULL;
238 const char *export_prefix = NULL;
240 static const struct option options[] = {
241 { "name", 1, NULL, 'n' },
242 { "path", 1, NULL, 'p' },
243 { "query", 1, NULL, 'q' },
244 { "attribute-walk", 0, NULL, 'a' },
245 { "export-db", 0, NULL, 'e' },
246 { "root", 0, NULL, 'r' },
247 { "device-id-of-file", 1, NULL, 'd' },
248 { "export", 0, NULL, 'x' },
249 { "export-prefix", 1, NULL, 'P' },
250 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
251 { "help", 0, NULL, 'h' },
258 ACTION_ATTRIBUTE_WALK,
260 ACTION_DEVICE_ID_FILE,
261 } action = ACTION_NONE;
270 } query = QUERY_NONE;
272 char path[PATH_SIZE] = "";
273 char name[PATH_SIZE] = "";
274 struct name_entry *name_loop;
280 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
284 dbg(udev, "option '%c'\n", option);
287 /* remove /dev if given */
288 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) == 0)
289 strlcpy(name, &optarg[strlen(udev_get_dev_path(udev))+1], sizeof(name));
291 strlcpy(name, optarg, sizeof(name));
292 remove_trailing_chars(name, '/');
293 dbg(udev, "name: %s\n", name);
296 /* remove /sys if given */
297 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) == 0)
298 strlcpy(path, &optarg[strlen(udev_get_sys_path(udev))], sizeof(path));
300 strlcpy(path, optarg, sizeof(path));
301 remove_trailing_chars(path, '/');
303 /* possibly resolve to real devpath */
304 if (sysfs_resolve_link(udev, path, sizeof(path)) != 0) {
305 char temp[PATH_SIZE];
308 /* also check if the parent is a link */
309 strlcpy(temp, path, sizeof(temp));
310 pos = strrchr(temp, '/');
312 char tail[PATH_SIZE];
314 strlcpy(tail, pos, sizeof(tail));
316 if (sysfs_resolve_link(udev, temp, sizeof(temp)) == 0) {
317 strlcpy(path, temp, sizeof(path));
318 strlcat(path, tail, sizeof(path));
322 dbg(udev, "path: %s\n", path);
325 action = ACTION_QUERY;
326 if (strcmp(optarg, "name") == 0) {
330 if (strcmp(optarg, "symlink") == 0) {
331 query = QUERY_SYMLINK;
334 if (strcmp(optarg, "path") == 0) {
338 if (strcmp(optarg, "env") == 0) {
342 if (strcmp(optarg, "all") == 0) {
346 fprintf(stderr, "unknown query type\n");
350 if (action == ACTION_NONE)
351 action = ACTION_ROOT;
355 action = ACTION_DEVICE_ID_FILE;
356 strlcpy(name, optarg, sizeof(name));
359 action = ACTION_ATTRIBUTE_WALK;
368 export_prefix = optarg;
371 printf("%s\n", VERSION);
374 printf("udevinfo, version %s\n", VERSION);
377 printf("Usage: udevadm info OPTIONS\n"
378 " --query=<type> query database for the specified value:\n"
379 " name name of device node\n"
380 " symlink pointing to node\n"
381 " path sysfs device path\n"
382 " env the device related imported environment\n"
384 " --path=<devpath> sysfs device path used for query or chain\n"
385 " --name=<name> node or symlink name used for query\n"
386 " --root prepend to query result or print udev_root\n"
387 " --attribute-walk print all key matches while walking along chain\n"
388 " of parent devices\n"
389 " --device-id-of-file=<file> print major/minor of underlying device\n"
390 " --export-db export the content of the udev database\n"
391 " --help print this text\n"
402 /* needs devpath or node/symlink name for query */
403 if (path[0] != '\0') {
404 udevice = udev_device_init(udev);
405 if (udevice == NULL) {
409 if (udev_db_get_device(udevice, path) != 0) {
410 fprintf(stderr, "no record for '%s' in database\n", path);
414 } else if (name[0] != '\0') {
415 if (lookup_device_by_name(udev, &udevice, name) != 0) {
416 fprintf(stderr, "node name not found\n");
421 fprintf(stderr, "query needs --path or node --name specified\n");
429 printf("%s/%s\n", udev_get_dev_path(udev), udevice->name);
431 printf("%s\n", udevice->name);
434 list_for_each_entry(name_loop, &udevice->symlink_list, node) {
435 char c = name_loop->node.next != &udevice->symlink_list ? ' ' : '\n';
438 printf("%s/%s%c", udev_get_dev_path(udev), name_loop->name, c);
440 printf("%s%c", name_loop->name, c);
444 printf("%s\n", udevice->dev->devpath);
447 list_for_each_entry(name_loop, &udevice->env_list, node)
448 printf("%s\n", name_loop->name);
451 print_record(udevice);
454 fprintf(stderr, "unknown query type\n");
458 case ACTION_ATTRIBUTE_WALK:
459 if (path[0] != '\0') {
460 if (print_device_chain(udev, path) != 0) {
461 fprintf(stderr, "no valid sysfs device found\n");
465 } else if (name[0] != '\0') {
466 if (lookup_device_by_name(udev, &udevice, name) != 0) {
467 fprintf(stderr, "node name not found\n");
471 if (print_device_chain(udev, udevice->dev->devpath) != 0) {
472 fprintf(stderr, "no valid sysfs device found\n");
477 fprintf(stderr, "attribute walk needs --path or node --name specified\n");
482 case ACTION_DEVICE_ID_FILE:
483 if (stat_device(name, export, export_prefix) != 0)
487 printf("%s\n", udev_get_dev_path(udev));
490 fprintf(stderr, "missing option\n");
496 udev_device_cleanup(udevice);