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)
135 struct udev_list_entry *list_entry;
137 printf("P: %s\n", udev_device_get_devpath(device));
139 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
140 str = udev_device_get_devnode(device);
142 printf("N: %s\n", &str[len+1]);
144 i = device_get_devlink_priority(device);
146 printf("L: %i\n", i);
148 i = device_get_num_fake_partitions(device);
152 i = device_get_ignore_remove(device);
156 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
157 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
158 printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
161 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
163 udev_list_entry_get_name(list_entry),
164 udev_list_entry_get_value(list_entry));
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 *udev_enumerate;
190 struct udev_list_entry *list_entry;
192 udev_enumerate = udev_enumerate_new(udev);
193 if (udev_enumerate == NULL)
195 udev_enumerate_scan_devices(udev_enumerate);
196 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
197 struct udev_device *device;
199 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
200 if (device != NULL) {
201 if (udev_device_get_devnode(device) != NULL)
202 print_record(device);
203 udev_device_unref(device);
206 udev_enumerate_unref(udev_enumerate);
210 int udevadm_info(struct udev *udev, int argc, char *argv[])
212 struct udev_device *device = NULL;
215 const char *export_prefix = NULL;
216 char path[UTIL_PATH_SIZE];
217 char name[UTIL_PATH_SIZE];
218 struct udev_list_entry *list_entry;
221 static const struct option options[] = {
222 { "name", required_argument, NULL, 'n' },
223 { "path", required_argument, NULL, 'p' },
224 { "query", required_argument, NULL, 'q' },
225 { "attribute-walk", no_argument, NULL, 'a' },
226 { "export-db", no_argument, NULL, 'e' },
227 { "root", no_argument, NULL, 'r' },
228 { "device-id-of-file", required_argument, NULL, 'd' },
229 { "export", no_argument, NULL, 'x' },
230 { "export-prefix", required_argument, NULL, 'P' },
231 { "version", no_argument, NULL, 1 }, /* -V outputs braindead format */
232 { "help", no_argument, NULL, 'h' },
239 ACTION_ATTRIBUTE_WALK,
241 ACTION_DEVICE_ID_FILE,
242 } action = ACTION_NONE;
251 } query = QUERY_NONE;
257 option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
261 dbg(udev, "option '%c'\n", option);
264 if (device != NULL) {
265 fprintf(stderr, "device already specified\n");
269 /* remove /dev if given */
270 if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0) {
271 util_strlcpy(name, udev_get_dev_path(udev), sizeof(name));
272 util_strlcat(name, "/", sizeof(name));
273 util_strlcat(name, optarg, sizeof(name));
275 util_strlcpy(name, optarg, sizeof(name));
277 util_remove_trailing_chars(name, '/');
278 if (stat(name, &statbuf) < 0) {
279 fprintf(stderr, "device node not found\n");
285 if (S_ISBLK(statbuf.st_mode)) {
287 } else if (S_ISCHR(statbuf.st_mode)) {
290 fprintf(stderr, "device node has wrong file type\n");
294 device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
295 if (device == NULL) {
296 fprintf(stderr, "device node not found\n");
303 if (device != NULL) {
304 fprintf(stderr, "device already specified\n");
308 /* add sys dir if needed */
309 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0) {
310 util_strlcpy(path, udev_get_sys_path(udev), sizeof(path));
311 util_strlcat(path, optarg, sizeof(path));
313 util_strlcpy(path, optarg, sizeof(path));
315 util_remove_trailing_chars(path, '/');
316 device = udev_device_new_from_syspath(udev, path);
317 if (device == NULL) {
318 fprintf(stderr, "device path not found\n");
324 action = ACTION_QUERY;
325 if (strcmp(optarg, "name") == 0) {
329 if (strcmp(optarg, "symlink") == 0) {
330 query = QUERY_SYMLINK;
333 if (strcmp(optarg, "path") == 0) {
337 if (strcmp(optarg, "env") == 0) {
341 if (strcmp(optarg, "all") == 0) {
345 fprintf(stderr, "unknown query type\n");
349 if (action == ACTION_NONE)
350 action = ACTION_ROOT;
354 action = ACTION_DEVICE_ID_FILE;
355 util_strlcpy(name, optarg, sizeof(name));
358 action = ACTION_ATTRIBUTE_WALK;
361 export_devices(udev);
367 export_prefix = optarg;
370 printf("%s\n", VERSION);
373 printf("udevinfo, version %s\n", VERSION);
376 printf("Usage: udevadm info OPTIONS\n"
377 " --query=<type> query device information:\n"
378 " name name of device node\n"
379 " symlink pointing to node\n"
380 " path sys device path\n"
381 " env the device related imported environment\n"
383 " --path=<syspath> sys device path used for query or attribute walk\n"
384 " --name=<name> node or symlink name used for query or attribute walk\n"
385 " --root prepend dev directory to path names\n"
386 " --attribute-walk print all key matches while walking along the chain\n"
387 " of parent devices\n"
388 " --device-id-of-file=<file> print major:minor of device containing this file\n"
389 " --export-db export the content of the udev database\n"
390 " --help print this text\n"
400 if (device == NULL) {
401 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
409 printf("%s\n", udev_device_get_devnode(device));
414 len = strlen(udev_get_dev_path(udev));
415 node = udev_device_get_devnode(device);
417 fprintf(stderr, "no device node found\n");
421 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
425 list_entry = udev_device_get_devlinks_list_entry(device);
426 while (list_entry != NULL) {
428 printf("%s", udev_list_entry_get_name(list_entry));
432 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
433 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
435 list_entry = udev_list_entry_get_next(list_entry);
436 if (list_entry != NULL)
442 printf("%s\n", udev_device_get_devpath(device));
445 list_entry = udev_device_get_properties_list_entry(device);
446 while (list_entry != NULL) {
447 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
448 list_entry = udev_list_entry_get_next(list_entry);
452 print_record(device);
455 fprintf(stderr, "unknown query type\n");
459 case ACTION_ATTRIBUTE_WALK:
460 if (device == NULL) {
461 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
465 print_device_chain(device);
467 case ACTION_DEVICE_ID_FILE:
468 if (stat_device(name, export, export_prefix) != 0)
472 printf("%s\n", udev_get_dev_path(udev));
475 fprintf(stderr, "missing option\n");
481 udev_device_unref(device);