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/>.
29 #include <sys/types.h>
33 static void print_all_attributes(struct udev_device *device, const char *key)
35 struct udev *udev = udev_device_get_udev(device);
39 dir = opendir(udev_device_get_syspath(device));
41 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
43 char filename[UTIL_PATH_SIZE];
47 if (dent->d_name[0] == '.')
50 if (strcmp(dent->d_name, "uevent") == 0)
52 if (strcmp(dent->d_name, "dev") == 0)
55 util_strlcpy(filename, udev_device_get_syspath(device), sizeof(filename));
56 util_strlcat(filename, "/", sizeof(filename));
57 util_strlcat(filename, dent->d_name, sizeof(filename));
58 if (lstat(filename, &statbuf) != 0)
60 if (S_ISLNK(statbuf.st_mode))
63 value = udev_device_get_attr_value(device, dent->d_name);
66 dbg(udev, "attr '%s'='%s'(%zi)\n", dent->d_name, value, len);
68 /* skip nonprintable attributes */
70 while (len > 0 && isprint(value[len-1]))
73 dbg(udev, "attribute value of '%s' non-printable, skip\n", dent->d_name);
77 printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
84 static int print_device_chain(struct udev_device *device)
86 struct udev_device *device_parent;
90 "Udevinfo starts with the device specified by the devpath and then\n"
91 "walks up the chain of parent devices. It prints for every device\n"
92 "found, all possible attributes in the udev rules key format.\n"
93 "A rule to match, can be composed by the attributes of the device\n"
94 "and the attributes from one single parent device.\n"
97 printf(" looking at device '%s':\n", udev_device_get_devpath(device));
98 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device));
99 str = udev_device_get_subsystem(device);
102 printf(" SUBSYSTEM==\"%s\"\n", str);
103 str = udev_device_get_driver(device);
106 printf(" DRIVER==\"%s\"\n", str);
107 print_all_attributes(device, "ATTR");
109 device_parent = device;
111 device_parent = udev_device_get_parent(device_parent);
112 if (device_parent == NULL)
114 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent));
115 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent));
116 str = udev_device_get_subsystem(device_parent);
119 printf(" SUBSYSTEMS==\"%s\"\n", str);
120 str = udev_device_get_driver(device_parent);
123 printf(" DRIVERS==\"%s\"\n", str);
124 print_all_attributes(device_parent, "ATTRS");
125 } while (device_parent != NULL);
130 static void print_record(struct udev_device *device)
134 struct udev_list_entry *list_entry;
136 printf("P: %s\n", udev_device_get_devpath(device));
138 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
139 printf("N: %s\n", &udev_device_get_devnode(device)[len+1]);
141 i = device_get_devlink_priority(device);
143 printf("L: %i\n", i);
145 i = device_get_num_fake_partitions(device);
149 i = device_get_ignore_remove(device);
153 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
154 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
155 printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
158 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
160 udev_list_entry_get_name(list_entry),
161 udev_list_entry_get_value(list_entry));
166 static int stat_device(const char *name, int export, const char *prefix)
170 if (stat(name, &statbuf) != 0)
176 printf("%sMAJOR=%d\n"
178 prefix, major(statbuf.st_dev),
179 prefix, minor(statbuf.st_dev));
181 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
185 static int export_devices(struct udev *udev)
187 struct udev_enumerate *udev_enumerate;
188 struct udev_list_entry *list_entry;
190 udev_enumerate = udev_enumerate_new(udev);
191 if (udev_enumerate == NULL)
193 udev_enumerate_scan_devices(udev_enumerate);
194 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
195 struct udev_device *device;
197 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
198 if (device != NULL) {
199 if (udev_device_get_devnode(device) != NULL)
200 print_record(device);
201 udev_device_unref(device);
204 udev_enumerate_unref(udev_enumerate);
208 int udevadm_info(struct udev *udev, int argc, char *argv[])
210 struct udev_device *device = NULL;
213 const char *export_prefix = NULL;
214 char path[UTIL_PATH_SIZE];
215 char name[UTIL_PATH_SIZE];
216 struct udev_list_entry *list_entry;
219 static const struct option options[] = {
220 { "name", required_argument, NULL, 'n' },
221 { "path", required_argument, NULL, 'p' },
222 { "query", required_argument, NULL, 'q' },
223 { "attribute-walk", no_argument, NULL, 'a' },
224 { "export-db", no_argument, NULL, 'e' },
225 { "root", no_argument, NULL, 'r' },
226 { "device-id-of-file", required_argument, NULL, 'd' },
227 { "export", no_argument, NULL, 'x' },
228 { "export-prefix", required_argument, NULL, 'P' },
229 { "version", no_argument, NULL, 1 }, /* -V outputs braindead format */
230 { "help", no_argument, NULL, 'h' },
237 ACTION_ATTRIBUTE_WALK,
239 ACTION_DEVICE_ID_FILE,
240 } action = ACTION_NONE;
249 } query = QUERY_NONE;
255 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
259 dbg(udev, "option '%c'\n", option);
262 if (device != NULL) {
263 fprintf(stderr, "device already specified\n");
267 /* remove /dev if given */
268 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0) {
269 util_strlcpy(name, udev_get_dev_path(udev), sizeof(name));
270 util_strlcat(name, "/", sizeof(name));
271 util_strlcat(name, optarg, sizeof(name));
273 util_strlcpy(name, optarg, sizeof(name));
275 util_remove_trailing_chars(name, '/');
276 if (stat(name, &statbuf) < 0) {
277 fprintf(stderr, "device node not found\n");
283 if (S_ISBLK(statbuf.st_mode)) {
285 } else if (S_ISCHR(statbuf.st_mode)) {
288 fprintf(stderr, "device node has wrong file type\n");
292 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
293 if (device == NULL) {
294 fprintf(stderr, "device node not found\n");
301 if (device != NULL) {
302 fprintf(stderr, "device already specified\n");
306 /* add sys dir if needed */
307 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0) {
308 util_strlcpy(path, udev_get_sys_path(udev), sizeof(path));
309 util_strlcat(path, optarg, sizeof(path));
311 util_strlcpy(path, optarg, sizeof(path));
313 util_remove_trailing_chars(path, '/');
314 device = udev_device_new_from_syspath(udev, path);
315 if (device == NULL) {
316 fprintf(stderr, "device path not found\n");
322 action = ACTION_QUERY;
323 if (strcmp(optarg, "name") == 0) {
327 if (strcmp(optarg, "symlink") == 0) {
328 query = QUERY_SYMLINK;
331 if (strcmp(optarg, "path") == 0) {
335 if (strcmp(optarg, "env") == 0) {
339 if (strcmp(optarg, "all") == 0) {
343 fprintf(stderr, "unknown query type\n");
347 if (action == ACTION_NONE)
348 action = ACTION_ROOT;
352 action = ACTION_DEVICE_ID_FILE;
353 util_strlcpy(name, optarg, sizeof(name));
356 action = ACTION_ATTRIBUTE_WALK;
359 export_devices(udev);
365 export_prefix = optarg;
368 printf("%s\n", VERSION);
371 printf("udevinfo, version %s\n", VERSION);
374 printf("Usage: udevadm info OPTIONS\n"
375 " --query=<type> query device information:\n"
376 " name name of device node\n"
377 " symlink pointing to node\n"
378 " path sys device path\n"
379 " env the device related imported environment\n"
381 " --path=<syspath> sys device path used for query or attribute walk\n"
382 " --name=<name> node or symlink name used for query or attribute walk\n"
383 " --root prepend dev directory to path names\n"
384 " --attribute-walk print all key matches while walking along the chain\n"
385 " of parent devices\n"
386 " --device-id-of-file=<file> print major:minor of device containing this file\n"
387 " --export-db export the content of the udev database\n"
388 " --help print this text\n"
398 if (device == NULL) {
399 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
407 printf("%s\n", udev_device_get_devnode(device));
412 len = strlen(udev_get_dev_path(udev));
413 node = udev_device_get_devnode(device);
415 fprintf(stderr, "no device node found\n");
419 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
423 list_entry = udev_device_get_devlinks_list_entry(device);
424 while (list_entry != NULL) {
426 printf("%s", udev_list_entry_get_name(list_entry));
430 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
431 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
433 list_entry = udev_list_entry_get_next(list_entry);
434 if (list_entry != NULL)
440 printf("%s\n", udev_device_get_devpath(device));
443 list_entry = udev_device_get_properties_list_entry(device);
444 while (list_entry != NULL) {
445 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
446 list_entry = udev_list_entry_get_next(list_entry);
450 print_record(device);
453 fprintf(stderr, "unknown query type\n");
457 case ACTION_ATTRIBUTE_WALK:
458 if (device == NULL) {
459 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
463 print_device_chain(device);
465 case ACTION_DEVICE_ID_FILE:
466 if (stat_device(name, export, export_prefix) != 0)
470 printf("%s\n", udev_get_dev_path(udev));
473 fprintf(stderr, "missing option\n");
479 udev_device_unref(device);