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 *enumerate;
187 struct udev_list_entry *list_entry;
189 enumerate = udev_enumerate_new_from_subsystems(udev, NULL);
190 if (enumerate == NULL)
192 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) {
193 struct udev_device *device;
195 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
196 if (device != NULL) {
197 if (udev_device_get_devnode(device) != NULL)
198 print_record(device);
199 udev_device_unref(device);
202 udev_enumerate_unref(enumerate);
206 int udevadm_info(struct udev *udev, int argc, char *argv[])
208 struct udev_device *device = NULL;
211 const char *export_prefix = NULL;
212 char path[UTIL_PATH_SIZE];
213 char name[UTIL_PATH_SIZE];
214 struct udev_list_entry *list_entry;
217 static const struct option options[] = {
218 { "name", 1, NULL, 'n' },
219 { "path", 1, NULL, 'p' },
220 { "query", 1, NULL, 'q' },
221 { "attribute-walk", 0, NULL, 'a' },
222 { "export-db", 0, NULL, 'e' },
223 { "root", 0, NULL, 'r' },
224 { "device-id-of-file", 1, NULL, 'd' },
225 { "export", 0, NULL, 'x' },
226 { "export-prefix", 1, NULL, 'P' },
227 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
228 { "help", 0, NULL, 'h' },
235 ACTION_ATTRIBUTE_WALK,
237 ACTION_DEVICE_ID_FILE,
238 } action = ACTION_NONE;
247 } query = QUERY_NONE;
253 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
257 dbg(udev, "option '%c'\n", option);
260 if (device != NULL) {
261 fprintf(stderr, "device already specified\n");
265 /* remove /dev if given */
266 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0) {
267 util_strlcpy(name, udev_get_dev_path(udev), sizeof(name));
268 util_strlcat(name, "/", sizeof(name));
269 util_strlcat(name, optarg, sizeof(name));
271 util_strlcpy(name, optarg, sizeof(name));
273 util_remove_trailing_chars(name, '/');
274 if (stat(name, &statbuf) < 0) {
275 fprintf(stderr, "device node not found\n");
281 if (S_ISBLK(statbuf.st_mode)) {
283 } else if (S_ISCHR(statbuf.st_mode)) {
286 fprintf(stderr, "device node has wrong file type\n");
290 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
291 if (device == NULL) {
292 fprintf(stderr, "device node not found\n");
299 if (device != NULL) {
300 fprintf(stderr, "device already specified\n");
304 /* add /sys if needed */
305 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0) {
306 util_strlcpy(path, udev_get_sys_path(udev), sizeof(path));
307 util_strlcat(path, optarg, sizeof(path));
309 util_strlcpy(path, optarg, sizeof(path));
311 util_remove_trailing_chars(path, '/');
312 device = udev_device_new_from_syspath(udev, path);
313 if (device == NULL) {
314 fprintf(stderr, "device path not found\n");
320 action = ACTION_QUERY;
321 if (strcmp(optarg, "name") == 0) {
325 if (strcmp(optarg, "symlink") == 0) {
326 query = QUERY_SYMLINK;
329 if (strcmp(optarg, "path") == 0) {
333 if (strcmp(optarg, "env") == 0) {
337 if (strcmp(optarg, "all") == 0) {
341 fprintf(stderr, "unknown query type\n");
345 if (action == ACTION_NONE)
346 action = ACTION_ROOT;
350 action = ACTION_DEVICE_ID_FILE;
351 util_strlcpy(name, optarg, sizeof(name));
354 action = ACTION_ATTRIBUTE_WALK;
357 export_devices(udev);
363 export_prefix = optarg;
366 printf("%s\n", VERSION);
369 printf("udevinfo, version %s\n", VERSION);
372 printf("Usage: udevadm info OPTIONS\n"
373 " --query=<type> query device information:\n"
374 " name name of device node\n"
375 " symlink pointing to node\n"
376 " path sys device path\n"
377 " env the device related imported environment\n"
379 " --path=<syspath> sys device path used for query or attribute walk\n"
380 " --name=<name> node or symlink name used for query or attribute walk\n"
381 " --root prepend dev directory to path names\n"
382 " --attribute-walk print all key matches while walking along the chain\n"
383 " of parent devices\n"
384 " --device-id-of-file=<file> print major:minor of device containing this file\n"
385 " --export-db export the content of the udev database\n"
386 " --help print this text\n"
396 if (device == NULL) {
397 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
405 printf("%s\n", udev_device_get_devnode(device));
409 len = strlen(udev_get_dev_path(udev));
410 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
414 list_entry = udev_device_get_devlinks_list_entry(device);
415 while (list_entry != NULL) {
417 printf("%s", udev_list_entry_get_name(list_entry));
421 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
422 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
424 list_entry = udev_list_entry_get_next(list_entry);
425 if (list_entry != NULL)
431 printf("%s\n", udev_device_get_devpath(device));
434 list_entry = udev_device_get_properties_list_entry(device);
435 while (list_entry != NULL) {
436 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
437 list_entry = udev_list_entry_get_next(list_entry);
441 print_record(device);
444 fprintf(stderr, "unknown query type\n");
448 case ACTION_ATTRIBUTE_WALK:
449 if (device == NULL) {
450 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
454 print_device_chain(device);
456 case ACTION_DEVICE_ID_FILE:
457 if (stat_device(name, export, export_prefix) != 0)
461 printf("%s\n", udev_get_dev_path(udev));
464 fprintf(stderr, "missing option\n");
470 udev_device_unref(device);