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 *devpath, const char *subsystem, const char *name,
172 struct udev_device *device;
174 device = udev_device_new_from_devpath(udev, devpath);
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)
187 LIST_HEAD(name_list);
189 struct name_entry *device;
192 count = udev_db_get_devices_by_name(udev, name, &name_list);
196 info(udev, "found %i devices for '%s'\n", count, name);
198 /* select the device that seems to match */
199 list_for_each_entry(device, &name_list, node) {
200 struct udevice *udevice_loop;
201 char filename[UTIL_PATH_SIZE];
204 udevice_loop = udev_device_init(udev);
205 if (udevice_loop == NULL)
207 if (udev_db_get_device(udevice_loop, device->name) != 0)
209 info(udev, "found db entry '%s'\n", device->name);
211 /* make sure, we don't get a link of a different device */
212 util_strlcpy(filename, udev_get_dev_path(udev), sizeof(filename));
213 util_strlcat(filename, "/", sizeof(filename));
214 util_strlcat(filename, name, sizeof(filename));
215 if (stat(filename, &statbuf) != 0)
217 if (major(udevice_loop->devt) > 0 && udevice_loop->devt != statbuf.st_rdev) {
218 info(udev, "skip '%s', dev_t doesn't match\n", udevice_loop->name);
222 *udevice = udevice_loop;
225 udev_device_cleanup(udevice_loop);
228 name_list_cleanup(udev, &name_list);
234 static int add_devlink_cb(struct udev_device *device, const char *value, void *data)
238 if (*links == NULL) {
239 *links = strdup(value);
243 asprintf(&str, "%s %s", *links, value);
250 static int add_devlink_noroot_cb(struct udev_device *device, const char *value, void *data)
254 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
255 value = &value[len+1];
256 return add_devlink_cb(device, value, data);
259 static int print_property_cb(struct udev_device *device, const char *key, const char *value, void *data)
261 printf("%s=%s\n", key, value);
265 static int stat_device(const char *name, int export, const char *prefix)
269 if (stat(name, &statbuf) != 0)
275 printf("%sMAJOR=%d\n"
277 prefix, major(statbuf.st_dev),
278 prefix, minor(statbuf.st_dev));
280 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
284 int udevadm_info(struct udev *udev, int argc, char *argv[])
286 struct udev_device *device = NULL;
289 const char *export_prefix = NULL;
290 char path[UTIL_PATH_SIZE];
291 char name[UTIL_PATH_SIZE];
295 static const struct option options[] = {
296 { "name", 1, NULL, 'n' },
297 { "path", 1, NULL, 'p' },
298 { "query", 1, NULL, 'q' },
299 { "attribute-walk", 0, NULL, 'a' },
300 { "export-db", 0, NULL, 'e' },
301 { "root", 0, NULL, 'r' },
302 { "device-id-of-file", 1, NULL, 'd' },
303 { "export", 0, NULL, 'x' },
304 { "export-prefix", 1, NULL, 'P' },
305 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
306 { "help", 0, NULL, 'h' },
313 ACTION_ATTRIBUTE_WALK,
315 ACTION_DEVICE_ID_FILE,
316 } action = ACTION_NONE;
325 } query = QUERY_NONE;
330 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
334 dbg(udev, "option '%c'\n", option);
337 if (device != NULL) {
338 fprintf(stderr, "device already specified\n");
342 /* remove /dev if given */
343 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) == 0)
344 util_strlcpy(name, &optarg[strlen(udev_get_dev_path(udev))+1], sizeof(name));
346 util_strlcpy(name, optarg, sizeof(name));
347 util_remove_trailing_chars(name, '/');
348 device = lookup_device_by_name(udev, name);
351 if (device != NULL) {
352 fprintf(stderr, "device already specified\n");
356 /* remove /sys if given */
357 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) == 0)
358 util_strlcpy(path, &optarg[strlen(udev_get_sys_path(udev))], sizeof(path));
360 util_strlcpy(path, optarg, sizeof(path));
361 util_remove_trailing_chars(path, '/');
362 device = udev_device_new_from_devpath(udev, path);
365 action = ACTION_QUERY;
366 if (strcmp(optarg, "name") == 0) {
370 if (strcmp(optarg, "symlink") == 0) {
371 query = QUERY_SYMLINK;
374 if (strcmp(optarg, "path") == 0) {
378 if (strcmp(optarg, "env") == 0) {
382 if (strcmp(optarg, "all") == 0) {
386 fprintf(stderr, "unknown query type\n");
390 if (action == ACTION_NONE)
391 action = ACTION_ROOT;
395 action = ACTION_DEVICE_ID_FILE;
396 util_strlcpy(name, optarg, sizeof(name));
399 action = ACTION_ATTRIBUTE_WALK;
402 udev_enumerate_devices(udev, NULL, export_all_cb, NULL);
408 export_prefix = optarg;
411 printf("%s\n", VERSION);
414 printf("udevinfo, version %s\n", VERSION);
417 printf("Usage: udevadm info OPTIONS\n"
418 " --query=<type> query database for the specified value:\n"
419 " name name of device node\n"
420 " symlink pointing to node\n"
421 " path sysfs device path\n"
422 " env the device related imported environment\n"
424 " --path=<devpath> sysfs device path used for query or chain\n"
425 " --name=<name> node or symlink name used for query\n"
426 " --root prepend to query result or print udev_root\n"
427 " --attribute-walk print all key matches while walking along chain\n"
428 " of parent devices\n"
429 " --device-id-of-file=<file> print major/minor of underlying device\n"
430 " --export-db export the content of the udev database\n"
431 " --help print this text\n"
441 if (device == NULL) {
442 fprintf(stderr, "query needs --path= or node --name= specified\n");
450 printf("%s\n", udev_device_get_devname(device));
454 len = strlen(udev_get_dev_path(udev));
455 printf("%s\n", &udev_device_get_devname(device)[len+1]);
461 udev_device_get_devlinks(device, add_devlink_cb, &links);
463 udev_device_get_devlinks(device, add_devlink_noroot_cb, &links);
464 printf("%s\n", links);
468 printf("%s\n", udev_device_get_devpath(device));
471 udev_device_get_properties(device, print_property_cb, NULL);
474 print_record(device);
477 fprintf(stderr, "unknown query type\n");
481 case ACTION_ATTRIBUTE_WALK:
482 if (device == NULL) {
483 fprintf(stderr, "attribute walk needs --path or node --name specified\n");
487 print_device_chain(device);
489 case ACTION_DEVICE_ID_FILE:
490 if (stat_device(name, export, export_prefix) != 0)
494 printf("%s\n", udev_get_dev_path(udev));
497 fprintf(stderr, "missing option\n");
503 udev_device_unref(device);