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)
38 dir = opendir(udev_device_get_syspath(device));
40 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
42 char filename[UTIL_PATH_SIZE];
46 if (dent->d_name[0] == '.')
49 if (strcmp(dent->d_name, "uevent") == 0)
51 if (strcmp(dent->d_name, "dev") == 0)
54 util_strlcpy(filename, udev_device_get_syspath(device), sizeof(filename));
55 util_strlcat(filename, "/", sizeof(filename));
56 util_strlcat(filename, dent->d_name, sizeof(filename));
57 if (lstat(filename, &statbuf) != 0)
59 if (S_ISLNK(statbuf.st_mode))
62 value = udev_device_get_attr_value(device, dent->d_name);
65 dbg(udev, "attr '%s'='%s'(%zi)\n", dent->d_name, value, len);
67 /* skip nonprintable attributes */
69 while (len > 0 && isprint(value[len-1]))
72 dbg(info, "attribute value of '%s' non-printable, skip\n", dent->d_name);
76 printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
83 static int print_device_chain(struct udev_device *device)
85 struct udev_device *device_parent;
89 "Udevinfo starts with the device specified by the devpath and then\n"
90 "walks up the chain of parent devices. It prints for every device\n"
91 "found, all possible attributes in the udev rules key format.\n"
92 "A rule to match, can be composed by the attributes of the device\n"
93 "and the attributes from one single parent device.\n"
96 printf(" looking at device '%s':\n", udev_device_get_devpath(device));
97 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device));
98 str = udev_device_get_subsystem(device);
101 printf(" SUBSYSTEM==\"%s\"\n", str);
102 str = udev_device_get_driver(device);
105 printf(" DRIVER==\"%s\"\n", str);
106 print_all_attributes(device, "ATTR");
108 device_parent = device;
110 device_parent = udev_device_get_parent(device_parent);
111 if (device_parent == NULL)
113 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent));
114 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent));
115 str = udev_device_get_subsystem(device_parent);
118 printf(" SUBSYSTEMS==\"%s\"\n", str);
119 str = udev_device_get_driver(device_parent);
122 printf(" DRIVERS==\"%s\"\n", str);
123 print_all_attributes(device_parent, "ATTRS");
124 } while (device_parent != NULL);
129 static void print_record(struct udev_device *device)
133 struct udev_list_entry *list_entry;
135 printf("P: %s\n", udev_device_get_devpath(device));
137 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
138 printf("N: %s\n", &udev_device_get_devnode(device)[len+1]);
140 i = device_get_devlink_priority(device);
142 printf("L: %i\n", i);
144 i = device_get_num_fake_partitions(device);
148 i = device_get_ignore_remove(device);
152 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
153 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
154 printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
157 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
159 udev_list_entry_get_name(list_entry),
160 udev_list_entry_get_value(list_entry));
165 static int stat_device(const char *name, int export, const char *prefix)
169 if (stat(name, &statbuf) != 0)
175 printf("%sMAJOR=%d\n"
177 prefix, major(statbuf.st_dev),
178 prefix, minor(statbuf.st_dev));
180 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
184 static int export_devices(struct udev *udev)
186 struct udev_enumerate *udev_enumerate;
187 struct udev_list_entry *list_entry;
189 udev_enumerate = udev_enumerate_new(udev);
190 if (udev_enumerate == NULL)
192 udev_enumerate_scan_devices(udev_enumerate, NULL);
193 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
194 struct udev_device *device;
196 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
197 if (device != NULL) {
198 if (udev_device_get_devnode(device) != NULL)
199 print_record(device);
200 udev_device_unref(device);
203 udev_enumerate_unref(udev_enumerate);
207 int udevadm_info(struct udev *udev, int argc, char *argv[])
209 struct udev_device *device = NULL;
212 const char *export_prefix = NULL;
213 char path[UTIL_PATH_SIZE];
214 char name[UTIL_PATH_SIZE];
215 struct udev_list_entry *list_entry;
218 static const struct option options[] = {
219 { "name", 1, NULL, 'n' },
220 { "path", 1, NULL, 'p' },
221 { "query", 1, NULL, 'q' },
222 { "attribute-walk", 0, NULL, 'a' },
223 { "export-db", 0, NULL, 'e' },
224 { "root", 0, NULL, 'r' },
225 { "device-id-of-file", 1, NULL, 'd' },
226 { "export", 0, NULL, 'x' },
227 { "export-prefix", 1, NULL, 'P' },
228 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
229 { "help", 0, NULL, 'h' },
236 ACTION_ATTRIBUTE_WALK,
238 ACTION_DEVICE_ID_FILE,
239 } action = ACTION_NONE;
248 } query = QUERY_NONE;
254 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
258 dbg(udev, "option '%c'\n", option);
261 if (device != NULL) {
262 fprintf(stderr, "device already specified\n");
266 /* remove /dev if given */
267 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0) {
268 util_strlcpy(name, udev_get_dev_path(udev), sizeof(name));
269 util_strlcat(name, "/", sizeof(name));
270 util_strlcat(name, optarg, sizeof(name));
272 util_strlcpy(name, optarg, sizeof(name));
274 util_remove_trailing_chars(name, '/');
275 if (stat(name, &statbuf) < 0) {
276 fprintf(stderr, "device node not found\n");
282 if (S_ISBLK(statbuf.st_mode)) {
284 } else if (S_ISCHR(statbuf.st_mode)) {
287 fprintf(stderr, "device node has wrong file type\n");
291 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
292 if (device == NULL) {
293 fprintf(stderr, "device node not found\n");
300 if (device != NULL) {
301 fprintf(stderr, "device already specified\n");
305 /* add sys dir if needed */
306 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0) {
307 util_strlcpy(path, udev_get_sys_path(udev), sizeof(path));
308 util_strlcat(path, optarg, sizeof(path));
310 util_strlcpy(path, optarg, sizeof(path));
312 util_remove_trailing_chars(path, '/');
313 device = udev_device_new_from_syspath(udev, path);
314 if (device == NULL) {
315 fprintf(stderr, "device path not found\n");
321 action = ACTION_QUERY;
322 if (strcmp(optarg, "name") == 0) {
326 if (strcmp(optarg, "symlink") == 0) {
327 query = QUERY_SYMLINK;
330 if (strcmp(optarg, "path") == 0) {
334 if (strcmp(optarg, "env") == 0) {
338 if (strcmp(optarg, "all") == 0) {
342 fprintf(stderr, "unknown query type\n");
346 if (action == ACTION_NONE)
347 action = ACTION_ROOT;
351 action = ACTION_DEVICE_ID_FILE;
352 util_strlcpy(name, optarg, sizeof(name));
355 action = ACTION_ATTRIBUTE_WALK;
358 export_devices(udev);
364 export_prefix = optarg;
367 printf("%s\n", VERSION);
370 printf("udevinfo, version %s\n", VERSION);
373 printf("Usage: udevadm info OPTIONS\n"
374 " --query=<type> query device information:\n"
375 " name name of device node\n"
376 " symlink pointing to node\n"
377 " path sys device path\n"
378 " env the device related imported environment\n"
380 " --path=<syspath> sys device path used for query or attribute walk\n"
381 " --name=<name> node or symlink name used for query or attribute walk\n"
382 " --root prepend dev directory to path names\n"
383 " --attribute-walk print all key matches while walking along the chain\n"
384 " of parent devices\n"
385 " --device-id-of-file=<file> print major:minor of device containing this file\n"
386 " --export-db export the content of the udev database\n"
387 " --help print this text\n"
397 if (device == NULL) {
398 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
406 printf("%s\n", udev_device_get_devnode(device));
410 len = strlen(udev_get_dev_path(udev));
411 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
415 list_entry = udev_device_get_devlinks_list_entry(device);
416 while (list_entry != NULL) {
418 printf("%s", udev_list_entry_get_name(list_entry));
422 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
423 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
425 list_entry = udev_list_entry_get_next(list_entry);
426 if (list_entry != NULL)
432 printf("%s\n", udev_device_get_devpath(device));
435 list_entry = udev_device_get_properties_list_entry(device);
436 while (list_entry != NULL) {
437 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
438 list_entry = udev_list_entry_get_next(list_entry);
442 print_record(device);
445 fprintf(stderr, "unknown query type\n");
449 case ACTION_ATTRIBUTE_WALK:
450 if (device == NULL) {
451 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
455 print_device_chain(device);
457 case ACTION_DEVICE_ID_FILE:
458 if (stat_device(name, export, export_prefix) != 0)
462 printf("%s\n", udev_get_dev_path(udev));
465 fprintf(stderr, "missing option\n");
471 udev_device_unref(device);