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_strscpyl(filename, sizeof(filename), udev_device_get_syspath(device), "/", dent->d_name, NULL);
56 if (lstat(filename, &statbuf) != 0)
58 if (S_ISLNK(statbuf.st_mode))
61 value = udev_device_get_sysattr_value(device, dent->d_name);
64 dbg(udev, "attr '%s'='%s'(%zi)\n", dent->d_name, value, len);
66 /* skip nonprintable attributes */
68 while (len > 0 && isprint(value[len-1]))
71 dbg(udev, "attribute value of '%s' non-printable, skip\n", dent->d_name);
75 printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
82 static int print_device_chain(struct udev_device *device)
84 struct udev_device *device_parent;
88 "Udevadm info starts with the device specified by the devpath and then\n"
89 "walks up the chain of parent devices. It prints for every device\n"
90 "found, all possible attributes in the udev rules key format.\n"
91 "A rule to match, can be composed by the attributes of the device\n"
92 "and the attributes from one single parent device.\n"
95 printf(" looking at device '%s':\n", udev_device_get_devpath(device));
96 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device));
97 str = udev_device_get_subsystem(device);
100 printf(" SUBSYSTEM==\"%s\"\n", str);
101 str = udev_device_get_driver(device);
104 printf(" DRIVER==\"%s\"\n", str);
105 print_all_attributes(device, "ATTR");
107 device_parent = device;
109 device_parent = udev_device_get_parent(device_parent);
110 if (device_parent == NULL)
112 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent));
113 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent));
114 str = udev_device_get_subsystem(device_parent);
117 printf(" SUBSYSTEMS==\"%s\"\n", str);
118 str = udev_device_get_driver(device_parent);
121 printf(" DRIVERS==\"%s\"\n", str);
122 print_all_attributes(device_parent, "ATTRS");
123 } while (device_parent != NULL);
128 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 str = udev_device_get_devnode(device);
140 printf("N: %s\n", &str[len+1]);
142 i = udev_device_get_devlink_priority(device);
144 printf("L: %i\n", i);
146 i = udev_device_get_num_fake_partitions(device);
150 i = udev_device_get_ignore_remove(device);
154 i = udev_device_get_watch_handle(device);
158 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
159 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
160 printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
163 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
165 udev_list_entry_get_name(list_entry),
166 udev_list_entry_get_value(list_entry));
170 static int stat_device(const char *name, int export, const char *prefix)
174 if (stat(name, &statbuf) != 0)
180 printf("%sMAJOR=%d\n"
182 prefix, major(statbuf.st_dev),
183 prefix, minor(statbuf.st_dev));
185 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
189 static int export_devices(struct udev *udev)
191 struct udev_enumerate *udev_enumerate;
192 struct udev_list_entry *list_entry;
194 udev_enumerate = udev_enumerate_new(udev);
195 if (udev_enumerate == NULL)
197 udev_enumerate_scan_devices(udev_enumerate);
198 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
199 struct udev_device *device;
201 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
202 if (device != NULL) {
203 print_record(device);
204 udev_device_unref(device);
207 udev_enumerate_unref(udev_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_entry *list_entry;
222 static const struct option options[] = {
223 { "name", required_argument, NULL, 'n' },
224 { "path", required_argument, NULL, 'p' },
225 { "query", required_argument, NULL, 'q' },
226 { "attribute-walk", no_argument, NULL, 'a' },
227 { "export-db", no_argument, NULL, 'e' },
228 { "root", no_argument, NULL, 'r' },
229 { "device-id-of-file", required_argument, NULL, 'd' },
230 { "export", no_argument, NULL, 'x' },
231 { "export-prefix", required_argument, NULL, 'P' },
232 { "version", no_argument, NULL, 'V' },
233 { "help", no_argument, 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_strscpyl(name, sizeof(name), udev_get_dev_path(udev), "/", optarg, NULL);
274 util_strscpy(name, sizeof(name), optarg);
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_strscpyl(path, sizeof(path), udev_get_sys_path(udev), optarg, NULL);
310 util_strscpy(path, sizeof(path), optarg);
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_strscpy(name, sizeof(name), optarg);
354 action = ACTION_ATTRIBUTE_WALK;
357 export_devices(udev);
363 export_prefix = optarg;
366 printf("%s\n", VERSION);
369 printf("Usage: udevadm info OPTIONS\n"
370 " --query=<type> query device information:\n"
371 " name name of device node\n"
372 " symlink pointing to node\n"
373 " path sys device path\n"
374 " env the device related imported environment\n"
376 " --path=<syspath> sys device path used for query or attribute walk\n"
377 " --name=<name> node or symlink name used for query or attribute walk\n"
378 " --root prepend dev directory to path names\n"
379 " --attribute-walk print all key matches while walking along the chain\n"
380 " of parent devices\n"
381 " --device-id-of-file=<file> print major:minor of device containing this file\n"
382 " --export-db export the content of the udev database\n"
392 if (device == NULL) {
393 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
401 printf("%s\n", udev_device_get_devnode(device));
406 len = strlen(udev_get_dev_path(udev));
407 node = udev_device_get_devnode(device);
409 fprintf(stderr, "no device node found\n");
413 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
417 list_entry = udev_device_get_devlinks_list_entry(device);
418 while (list_entry != NULL) {
420 printf("%s", udev_list_entry_get_name(list_entry));
424 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
425 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
427 list_entry = udev_list_entry_get_next(list_entry);
428 if (list_entry != NULL)
434 printf("%s\n", udev_device_get_devpath(device));
437 list_entry = udev_device_get_properties_list_entry(device);
438 while (list_entry != NULL) {
439 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
440 list_entry = udev_list_entry_get_next(list_entry);
444 print_record(device);
447 fprintf(stderr, "unknown query type\n");
451 case ACTION_ATTRIBUTE_WALK:
452 if (device == NULL) {
453 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
457 print_device_chain(device);
459 case ACTION_DEVICE_ID_FILE:
460 if (stat_device(name, export, export_prefix) != 0)
464 printf("%s\n", udev_get_dev_path(udev));
467 fprintf(stderr, "missing option\n");
473 udev_device_unref(device);