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_device *device, const char *key)
40 dir = opendir(udev_device_get_syspath(device));
42 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
44 char filename[UTIL_PATH_SIZE];
48 if (dent->d_name[0] == '.')
51 if (strcmp(dent->d_name, "uevent") == 0)
53 if (strcmp(dent->d_name, "dev") == 0)
56 util_strlcpy(filename, udev_device_get_syspath(device), sizeof(filename));
57 util_strlcat(filename, "/", sizeof(filename));
58 util_strlcat(filename, dent->d_name, sizeof(filename));
59 if (lstat(filename, &statbuf) != 0)
61 if (S_ISLNK(statbuf.st_mode))
64 value = udev_device_get_attr_value(device, dent->d_name);
67 dbg(udev, "attr '%s'='%s'(%zi)\n", dent->d_name, value, len);
69 /* skip nonprintable attributes */
71 while (len > 0 && isprint(value[len-1]))
74 dbg(info, "attribute value of '%s' non-printable, skip\n", dent->d_name);
78 printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
85 static int print_device_chain(struct udev_device *device)
87 struct udev_device *device_parent;
91 "Udevinfo starts with the device specified by the devpath and then\n"
92 "walks up the chain of parent devices. It prints for every device\n"
93 "found, all possible attributes in the udev rules key format.\n"
94 "A rule to match, can be composed by the attributes of the device\n"
95 "and the attributes from one single parent device.\n"
98 printf(" looking at device '%s':\n", udev_device_get_devpath(device));
99 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device));
100 str = udev_device_get_subsystem(device);
103 printf(" SUBSYSTEM==\"%s\"\n", str);
104 str = udev_device_get_driver(device);
107 printf(" DRIVER==\"%s\"\n", str);
108 print_all_attributes(device, "ATTR");
110 device_parent = device;
112 device_parent = udev_device_get_parent(device_parent);
113 if (device_parent == NULL)
115 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent));
116 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent));
117 str = udev_device_get_subsystem(device_parent);
120 printf(" SUBSYSTEMS==\"%s\"\n", str);
121 str = udev_device_get_driver(device_parent);
124 printf(" DRIVERS==\"%s\"\n", str);
125 print_all_attributes(device_parent, "ATTRS");
126 } while (device_parent != NULL);
131 static int print_record_devlinks_cb(struct udev_device *device, const char *value, void *data)
135 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
136 printf("S: %s\n", &value[len+1]);
140 static int print_record_properties_cb(struct udev_device *device, const char *key, const char *value, void *data)
142 printf("E: %s=%s\n", key, value);
146 static void print_record(struct udev_device *device)
151 printf("P: %s\n", udev_device_get_devpath(device));
152 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
153 printf("N: %s\n", &udev_device_get_devname(device)[len+1]);
154 i = device_get_devlink_priority(device);
156 printf("L: %i\n", i);
157 i = device_get_num_fake_partitions(device);
160 i = device_get_ignore_remove(device);
163 udev_device_get_devlinks(device, print_record_devlinks_cb, NULL);
164 udev_device_get_properties(device, print_record_properties_cb, NULL);
168 static int export_all_cb(struct udev *udev,
169 const char *syspath, const char *subsystem, const char *name,
172 struct udev_device *device;
174 device = udev_device_new_from_syspath(udev, syspath);
177 if (udev_device_get_devname(device) != NULL)
178 print_record(device);
179 udev_device_unref(device);
183 static struct udev_device *lookup_device_by_name(struct udev *udev, const char *name)
185 struct udev_device *udev_device = NULL;
186 LIST_HEAD(name_list);
188 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 matches */
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);
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);
218 util_strlcpy(filename, udev_get_sys_path(udev), sizeof(filename));
219 util_strlcat(filename, udevice_loop->dev->devpath, sizeof(filename));
220 udev_device = udev_device_new_from_syspath(udev, filename);
221 udev_device_cleanup(udevice_loop);
224 udev_device_cleanup(udevice_loop);
227 name_list_cleanup(udev, &name_list);
231 static int add_devlink_cb(struct udev_device *device, const char *value, void *data)
235 if (*links == NULL) {
236 *links = strdup(value);
240 asprintf(&str, "%s %s", *links, value);
247 static int add_devlink_noroot_cb(struct udev_device *device, const char *value, void *data)
251 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
252 value = &value[len+1];
253 return add_devlink_cb(device, value, data);
256 static int print_property_cb(struct udev_device *device, const char *key, const char *value, void *data)
258 printf("%s=%s\n", key, value);
262 static int stat_device(const char *name, int export, const char *prefix)
266 if (stat(name, &statbuf) != 0)
272 printf("%sMAJOR=%d\n"
274 prefix, major(statbuf.st_dev),
275 prefix, minor(statbuf.st_dev));
277 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
281 int udevadm_info(struct udev *udev, int argc, char *argv[])
283 struct udev_device *device = NULL;
286 const char *export_prefix = NULL;
287 char path[UTIL_PATH_SIZE];
288 char name[UTIL_PATH_SIZE];
292 static const struct option options[] = {
293 { "name", 1, NULL, 'n' },
294 { "path", 1, NULL, 'p' },
295 { "query", 1, NULL, 'q' },
296 { "attribute-walk", 0, NULL, 'a' },
297 { "export-db", 0, NULL, 'e' },
298 { "root", 0, NULL, 'r' },
299 { "device-id-of-file", 1, NULL, 'd' },
300 { "export", 0, NULL, 'x' },
301 { "export-prefix", 1, NULL, 'P' },
302 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
303 { "help", 0, NULL, 'h' },
310 ACTION_ATTRIBUTE_WALK,
312 ACTION_DEVICE_ID_FILE,
313 } action = ACTION_NONE;
322 } query = QUERY_NONE;
327 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
331 dbg(udev, "option '%c'\n", option);
334 if (device != NULL) {
335 fprintf(stderr, "device already specified\n");
339 /* remove /dev if given */
340 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) == 0)
341 util_strlcpy(name, &optarg[strlen(udev_get_dev_path(udev))+1], sizeof(name));
343 util_strlcpy(name, optarg, sizeof(name));
344 util_remove_trailing_chars(name, '/');
345 device = lookup_device_by_name(udev, name);
348 if (device != NULL) {
349 fprintf(stderr, "device already specified\n");
353 /* add /sys if needed */
354 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0) {
355 util_strlcpy(path, udev_get_sys_path(udev), sizeof(path));
356 util_strlcat(path, optarg, sizeof(path));
358 util_strlcpy(path, optarg, sizeof(path));
360 util_remove_trailing_chars(path, '/');
361 device = udev_device_new_from_syspath(udev, path);
364 action = ACTION_QUERY;
365 if (strcmp(optarg, "name") == 0) {
369 if (strcmp(optarg, "symlink") == 0) {
370 query = QUERY_SYMLINK;
373 if (strcmp(optarg, "path") == 0) {
377 if (strcmp(optarg, "env") == 0) {
381 if (strcmp(optarg, "all") == 0) {
385 fprintf(stderr, "unknown query type\n");
389 if (action == ACTION_NONE)
390 action = ACTION_ROOT;
394 action = ACTION_DEVICE_ID_FILE;
395 util_strlcpy(name, optarg, sizeof(name));
398 action = ACTION_ATTRIBUTE_WALK;
401 udev_enumerate_devices(udev, NULL, export_all_cb, NULL);
407 export_prefix = optarg;
410 printf("%s\n", VERSION);
413 printf("udevinfo, version %s\n", VERSION);
416 printf("Usage: udevadm info OPTIONS\n"
417 " --query=<type> query database for the specified value:\n"
418 " name name of device node\n"
419 " symlink pointing to node\n"
420 " path sysfs device path\n"
421 " env the device related imported environment\n"
423 " --path=<devpath> sysfs device path used for query or chain\n"
424 " --name=<name> node or symlink name used for query\n"
425 " --root prepend to query result or print udev_root\n"
426 " --attribute-walk print all key matches while walking along chain\n"
427 " of parent devices\n"
428 " --device-id-of-file=<file> print major/minor of underlying device\n"
429 " --export-db export the content of the udev database\n"
430 " --help print this text\n"
440 if (device == NULL) {
441 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
449 printf("%s\n", udev_device_get_devname(device));
453 len = strlen(udev_get_dev_path(udev));
454 printf("%s\n", &udev_device_get_devname(device)[len+1]);
460 udev_device_get_devlinks(device, add_devlink_cb, &links);
462 udev_device_get_devlinks(device, add_devlink_noroot_cb, &links);
463 printf("%s\n", links);
467 printf("%s\n", udev_device_get_devpath(device));
470 udev_device_get_properties(device, print_property_cb, NULL);
473 print_record(device);
476 fprintf(stderr, "unknown query type\n");
480 case ACTION_ATTRIBUTE_WALK:
481 if (device == NULL) {
482 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
486 print_device_chain(device);
488 case ACTION_DEVICE_ID_FILE:
489 if (stat_device(name, export, export_prefix) != 0)
493 printf("%s\n", udev_get_dev_path(udev));
496 fprintf(stderr, "missing option\n");
502 udev_device_unref(device);