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 /* remove trailing newlines */
79 while (len && value[len-1] == '\n')
82 /* skip nonprintable attributes */
83 while (len && isprint(value[len-1]))
86 dbg(udev, "attribute value of '%s' non-printable, skip\n", dent->d_name);
90 printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
96 static int print_device_chain(struct udev *udev, const char *devpath)
98 struct sysfs_device *dev;
100 dev = sysfs_device_get(udev, devpath);
105 "Udevinfo starts with the device specified by the devpath and then\n"
106 "walks up the chain of parent devices. It prints for every device\n"
107 "found, all possible attributes in the udev rules key format.\n"
108 "A rule to match, can be composed by the attributes of the device\n"
109 "and the attributes from one single parent device.\n"
112 printf(" looking at device '%s':\n", dev->devpath);
113 printf(" KERNEL==\"%s\"\n", dev->kernel);
114 printf(" SUBSYSTEM==\"%s\"\n", dev->subsystem);
115 printf(" DRIVER==\"%s\"\n", dev->driver);
116 print_all_attributes(udev, dev->devpath, "ATTR");
118 /* walk up the chain of devices */
120 dev = sysfs_device_get_parent(udev, dev);
123 printf(" looking at parent device '%s':\n", dev->devpath);
124 printf(" KERNELS==\"%s\"\n", dev->kernel);
125 printf(" SUBSYSTEMS==\"%s\"\n", dev->subsystem);
126 printf(" DRIVERS==\"%s\"\n", dev->driver);
128 print_all_attributes(udev, dev->devpath, "ATTRS");
134 static void print_record(struct udevice *udevice)
136 struct name_entry *name_loop;
138 printf("P: %s\n", udevice->dev->devpath);
139 printf("N: %s\n", udevice->name);
140 list_for_each_entry(name_loop, &udevice->symlink_list, node)
141 printf("S: %s\n", name_loop->name);
142 if (udevice->link_priority != 0)
143 printf("L: %i\n", udevice->link_priority);
144 if (udevice->partitions != 0)
145 printf("A:%u\n", udevice->partitions);
146 if (udevice->ignore_remove)
147 printf("R:%u\n", udevice->ignore_remove);
148 list_for_each_entry(name_loop, &udevice->env_list, node)
149 printf("E: %s\n", name_loop->name);
152 static void export_db(struct udev *udev)
154 LIST_HEAD(name_list);
155 struct name_entry *name_loop;
157 udev_db_get_all_entries(udev, &name_list);
158 list_for_each_entry(name_loop, &name_list, node) {
159 struct udevice *udevice_db;
161 udevice_db = udev_device_init(udev);
162 if (udevice_db == NULL)
164 if (udev_db_get_device(udevice_db, name_loop->name) == 0)
165 print_record(udevice_db);
167 udev_device_cleanup(udevice_db);
169 name_list_cleanup(udev, &name_list);
172 static int lookup_device_by_name(struct udev *udev, struct udevice **udevice, const char *name)
174 LIST_HEAD(name_list);
176 struct name_entry *device;
179 count = udev_db_get_devices_by_name(udev, name, &name_list);
183 info(udev, "found %i devices for '%s'\n", count, name);
185 /* select the device that seems to match */
186 list_for_each_entry(device, &name_list, node) {
187 struct udevice *udevice_loop;
188 char filename[PATH_SIZE];
191 udevice_loop = udev_device_init(udev);
192 if (udevice_loop == NULL)
194 if (udev_db_get_device(udevice_loop, device->name) != 0)
196 info(udev, "found db entry '%s'\n", device->name);
198 /* make sure, we don't get a link of a different device */
199 strlcpy(filename, udev_get_dev_path(udev), sizeof(filename));
200 strlcat(filename, "/", sizeof(filename));
201 strlcat(filename, name, sizeof(filename));
202 if (stat(filename, &statbuf) != 0)
204 if (major(udevice_loop->devt) > 0 && udevice_loop->devt != statbuf.st_rdev) {
205 info(udev, "skip '%s', dev_t doesn't match\n", udevice_loop->name);
209 *udevice = udevice_loop;
212 udev_device_cleanup(udevice_loop);
215 name_list_cleanup(udev, &name_list);
219 static int stat_device(const char *name, int export, const char *prefix)
223 if (stat(name, &statbuf) != 0)
229 printf("%sMAJOR=%d\n"
231 prefix, major(statbuf.st_dev),
232 prefix, minor(statbuf.st_dev));
234 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
238 int udevadm_info(struct udev *udev, int argc, char *argv[])
240 struct udevice *udevice = NULL;
243 const char *export_prefix = NULL;
245 static const struct option options[] = {
246 { "name", 1, NULL, 'n' },
247 { "path", 1, NULL, 'p' },
248 { "query", 1, NULL, 'q' },
249 { "attribute-walk", 0, NULL, 'a' },
250 { "export-db", 0, NULL, 'e' },
251 { "root", 0, NULL, 'r' },
252 { "device-id-of-file", 1, NULL, 'd' },
253 { "export", 0, NULL, 'x' },
254 { "export-prefix", 1, NULL, 'P' },
255 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
256 { "help", 0, NULL, 'h' },
263 ACTION_ATTRIBUTE_WALK,
265 ACTION_DEVICE_ID_FILE,
266 } action = ACTION_NONE;
275 } query = QUERY_NONE;
277 char path[PATH_SIZE] = "";
278 char name[PATH_SIZE] = "";
279 struct name_entry *name_loop;
285 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
289 dbg(udev, "option '%c'\n", option);
292 /* remove /dev if given */
293 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) == 0)
294 strlcpy(name, &optarg[strlen(udev_get_dev_path(udev))+1], sizeof(name));
296 strlcpy(name, optarg, sizeof(name));
297 remove_trailing_chars(name, '/');
298 dbg(udev, "name: %s\n", name);
301 /* remove /sys if given */
302 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) == 0)
303 strlcpy(path, &optarg[strlen(udev_get_sys_path(udev))], sizeof(path));
305 strlcpy(path, optarg, sizeof(path));
306 remove_trailing_chars(path, '/');
308 /* possibly resolve to real devpath */
309 if (sysfs_resolve_link(udev, path, sizeof(path)) != 0) {
310 char temp[PATH_SIZE];
313 /* also check if the parent is a link */
314 strlcpy(temp, path, sizeof(temp));
315 pos = strrchr(temp, '/');
317 char tail[PATH_SIZE];
319 strlcpy(tail, pos, sizeof(tail));
321 if (sysfs_resolve_link(udev, temp, sizeof(temp)) == 0) {
322 strlcpy(path, temp, sizeof(path));
323 strlcat(path, tail, sizeof(path));
327 dbg(udev, "path: %s\n", path);
330 action = ACTION_QUERY;
331 if (strcmp(optarg, "name") == 0) {
335 if (strcmp(optarg, "symlink") == 0) {
336 query = QUERY_SYMLINK;
339 if (strcmp(optarg, "path") == 0) {
343 if (strcmp(optarg, "env") == 0) {
347 if (strcmp(optarg, "all") == 0) {
351 fprintf(stderr, "unknown query type\n");
355 if (action == ACTION_NONE)
356 action = ACTION_ROOT;
360 action = ACTION_DEVICE_ID_FILE;
361 strlcpy(name, optarg, sizeof(name));
364 action = ACTION_ATTRIBUTE_WALK;
373 export_prefix = optarg;
376 printf("%s\n", VERSION);
379 printf("udevinfo, version %s\n", VERSION);
382 printf("Usage: udevadm info OPTIONS\n"
383 " --query=<type> query database for the specified value:\n"
384 " name name of device node\n"
385 " symlink pointing to node\n"
386 " path sysfs device path\n"
387 " env the device related imported environment\n"
389 " --path=<devpath> sysfs device path used for query or chain\n"
390 " --name=<name> node or symlink name used for query\n"
391 " --root prepend to query result or print udev_root\n"
392 " --attribute-walk print all key matches while walking along chain\n"
393 " of parent devices\n"
394 " --device-id-of-file=<file> print major/minor of underlying device\n"
395 " --export-db export the content of the udev database\n"
396 " --help print this text\n"
407 /* needs devpath or node/symlink name for query */
408 if (path[0] != '\0') {
409 udevice = udev_device_init(udev);
410 if (udevice == NULL) {
414 if (udev_db_get_device(udevice, path) != 0) {
415 fprintf(stderr, "no record for '%s' in database\n", path);
419 } else if (name[0] != '\0') {
420 if (lookup_device_by_name(udev, &udevice, name) != 0) {
421 fprintf(stderr, "node name not found\n");
426 fprintf(stderr, "query needs --path or node --name specified\n");
434 printf("%s/%s\n", udev_get_dev_path(udev), udevice->name);
436 printf("%s\n", udevice->name);
439 list_for_each_entry(name_loop, &udevice->symlink_list, node) {
440 char c = name_loop->node.next != &udevice->symlink_list ? ' ' : '\n';
443 printf("%s/%s%c", udev_get_dev_path(udev), name_loop->name, c);
445 printf("%s%c", name_loop->name, c);
449 printf("%s\n", udevice->dev->devpath);
452 list_for_each_entry(name_loop, &udevice->env_list, node)
453 printf("%s\n", name_loop->name);
456 print_record(udevice);
459 fprintf(stderr, "unknown query type\n");
463 case ACTION_ATTRIBUTE_WALK:
464 if (path[0] != '\0') {
465 if (print_device_chain(udev, path) != 0) {
466 fprintf(stderr, "no valid sysfs device found\n");
470 } else if (name[0] != '\0') {
471 if (lookup_device_by_name(udev, &udevice, name) != 0) {
472 fprintf(stderr, "node name not found\n");
476 if (print_device_chain(udev, udevice->dev->devpath) != 0) {
477 fprintf(stderr, "no valid sysfs device found\n");
482 fprintf(stderr, "attribute walk needs --path or node --name specified\n");
487 case ACTION_DEVICE_ID_FILE:
488 if (stat_device(name, export, export_prefix) != 0)
492 printf("%s\n", udev_get_dev_path(udev));
495 fprintf(stderr, "missing option\n");
501 udev_device_cleanup(udevice);