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 *list;
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 list = udev_device_get_devlinks_list(device);
153 while (list != NULL) {
154 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
155 printf("S: %s\n", &udev_list_entry_get_name(list)[len+1]);
156 list = udev_list_entry_get_next(list);
159 list = udev_device_get_properties_list(device);
160 while (list != NULL) {
161 printf("E: %s=%s\n", udev_list_entry_get_name(list), udev_list_entry_get_value(list));
162 list = udev_list_entry_get_next(list);
168 static int stat_device(const char *name, int export, const char *prefix)
172 if (stat(name, &statbuf) != 0)
178 printf("%sMAJOR=%d\n"
180 prefix, major(statbuf.st_dev),
181 prefix, minor(statbuf.st_dev));
183 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
187 static int export_devices(struct udev *udev)
189 struct udev_enumerate *enumerate;
190 struct udev_list *list;
192 enumerate = udev_enumerate_new_from_subsystems(udev, NULL);
193 if (enumerate == NULL)
195 list = udev_enumerate_get_list(enumerate);
196 while (list != NULL) {
197 struct udev_device *device;
199 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list));
200 if (device != NULL) {
201 if (udev_device_get_devnode(device) != NULL)
202 print_record(device);
203 udev_device_unref(device);
205 list = udev_list_entry_get_next(list);
207 udev_enumerate_unref(enumerate);
211 int udevadm_info(struct udev *udev, int argc, char *argv[])
213 struct udev_device *device = NULL;
216 const char *export_prefix = NULL;
217 char path[UTIL_PATH_SIZE];
218 char name[UTIL_PATH_SIZE];
219 struct udev_list *list;
222 static const struct option options[] = {
223 { "name", 1, NULL, 'n' },
224 { "path", 1, NULL, 'p' },
225 { "query", 1, NULL, 'q' },
226 { "attribute-walk", 0, NULL, 'a' },
227 { "export-db", 0, NULL, 'e' },
228 { "root", 0, NULL, 'r' },
229 { "device-id-of-file", 1, NULL, 'd' },
230 { "export", 0, NULL, 'x' },
231 { "export-prefix", 1, NULL, 'P' },
232 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
233 { "help", 0, NULL, 'h' },
240 ACTION_ATTRIBUTE_WALK,
242 ACTION_DEVICE_ID_FILE,
243 } action = ACTION_NONE;
252 } query = QUERY_NONE;
258 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
262 dbg(udev, "option '%c'\n", option);
265 if (device != NULL) {
266 fprintf(stderr, "device already specified\n");
270 /* remove /dev if given */
271 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0) {
272 util_strlcpy(name, udev_get_dev_path(udev), sizeof(name));
273 util_strlcat(name, "/", sizeof(name));
274 util_strlcat(name, optarg, sizeof(name));
276 util_strlcpy(name, optarg, sizeof(name));
278 util_remove_trailing_chars(name, '/');
279 if (stat(name, &statbuf) < 0) {
280 fprintf(stderr, "device node not found\n");
286 if (S_ISBLK(statbuf.st_mode)) {
288 } else if (S_ISCHR(statbuf.st_mode)) {
291 fprintf(stderr, "device node has wrong file type\n");
295 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
296 if (device == NULL) {
297 fprintf(stderr, "device node not found\n");
304 if (device != NULL) {
305 fprintf(stderr, "device already specified\n");
309 /* add /sys if needed */
310 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0) {
311 util_strlcpy(path, udev_get_sys_path(udev), sizeof(path));
312 util_strlcat(path, optarg, sizeof(path));
314 util_strlcpy(path, optarg, sizeof(path));
316 util_remove_trailing_chars(path, '/');
317 device = udev_device_new_from_syspath(udev, path);
318 if (device == NULL) {
319 fprintf(stderr, "device path not found\n");
325 action = ACTION_QUERY;
326 if (strcmp(optarg, "name") == 0) {
330 if (strcmp(optarg, "symlink") == 0) {
331 query = QUERY_SYMLINK;
334 if (strcmp(optarg, "path") == 0) {
338 if (strcmp(optarg, "env") == 0) {
342 if (strcmp(optarg, "all") == 0) {
346 fprintf(stderr, "unknown query type\n");
350 if (action == ACTION_NONE)
351 action = ACTION_ROOT;
355 action = ACTION_DEVICE_ID_FILE;
356 util_strlcpy(name, optarg, sizeof(name));
359 action = ACTION_ATTRIBUTE_WALK;
362 export_devices(udev);
368 export_prefix = optarg;
371 printf("%s\n", VERSION);
374 printf("udevinfo, version %s\n", VERSION);
377 printf("Usage: udevadm info OPTIONS\n"
378 " --query=<type> query device information:\n"
379 " name name of device node\n"
380 " symlink pointing to node\n"
381 " path sys device path\n"
382 " env the device related imported environment\n"
384 " --path=<syspath> sys device path used for query or attribute walk\n"
385 " --name=<name> node or symlink name used for query or attribute walk\n"
386 " --root prepend dev directory to path names\n"
387 " --attribute-walk print all key matches while walking along the chain\n"
388 " of parent devices\n"
389 " --device-id-of-file=<file> print major:minor of device containing this file\n"
390 " --export-db export the content of the udev database\n"
391 " --help print this text\n"
401 if (device == NULL) {
402 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
410 printf("%s\n", udev_device_get_devnode(device));
414 len = strlen(udev_get_dev_path(udev));
415 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
419 list = udev_device_get_devlinks_list(device);
420 while (list != NULL) {
422 printf("%s", udev_list_entry_get_name(list));
426 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
427 printf("%s", &udev_list_entry_get_name(list)[len+1]);
429 list = udev_list_entry_get_next(list);
436 printf("%s\n", udev_device_get_devpath(device));
439 list = udev_device_get_properties_list(device);
440 while (list != NULL) {
441 printf("%s=%s\n", udev_list_entry_get_name(list), udev_list_entry_get_value(list));
442 list = udev_list_entry_get_next(list);
446 print_record(device);
449 fprintf(stderr, "unknown query type\n");
453 case ACTION_ATTRIBUTE_WALK:
454 if (device == NULL) {
455 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
459 print_device_chain(device);
461 case ACTION_DEVICE_ID_FILE:
462 if (stat_device(name, export, export_prefix) != 0)
466 printf("%s\n", udev_get_dev_path(udev));
469 fprintf(stderr, "missing option\n");
475 udev_device_unref(device);