2 * udevinfo.c - fetches attributes for a device
4 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation version 2 of the License.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 675 Mass Ave, Cambridge, MA 02139, USA.
29 #include "libsysfs/sysfs/libsysfs.h"
30 #include "udev_libc_wrapper.h"
32 #include "udev_utils.h"
33 #include "udev_version.h"
39 void log_message (int priority, const char *format, ...)
43 if (priority > udev_log_priority)
46 va_start(args, format);
47 vsyslog(priority, format, args);
52 static void print_all_attributes(struct dlist *attr_list)
54 struct sysfs_attribute *attr;
55 char value[VALUE_SIZE];
58 dlist_for_each_data(attr_list, attr, struct sysfs_attribute) {
59 if (attr->value == NULL)
61 len = strlcpy(value, attr->value, sizeof(value));
62 if (len >= sizeof(value)) {
63 dbg("attribute value of '%s' too long, skip", attr->name);
67 /* remove trailing newlines */
68 while (len && value[len-1] == '\n')
70 /* skip nonprintable attributes */
71 while (len && isprint(value[len-1]))
74 dbg("attribute value of '%s' non-printable, skip", attr->name);
77 replace_untrusted_chars(value);
78 printf(" SYSFS{%s}==\"%s\"\n", attr->name, value);
83 static int print_record(struct udevice *udev)
85 struct name_entry *name_loop;
87 printf("P: %s\n", udev->devpath);
88 printf("N: %s\n", udev->name);
89 list_for_each_entry(name_loop, &udev->symlink_list, node)
90 printf("S: %s\n", name_loop->name);
95 static int print_device_chain(const char *path)
97 struct sysfs_class_device *class_dev;
98 struct sysfs_class_device *class_dev_parent;
99 struct sysfs_attribute *attr;
100 struct sysfs_device *sysfs_dev;
101 struct dlist *attr_list;
104 /* get the class dev */
105 class_dev = sysfs_open_class_device_path(path);
106 if (class_dev == NULL) {
107 fprintf(stderr, "couldn't get the class device\n");
111 printf("\nudevinfo starts with the device the node belongs to and then walks up the\n"
112 "device chain, to print for every device found, all possibly useful attributes\n"
113 "in the udev key format.\n"
114 "Only attributes within one device section may be used together in one rule,\n"
115 "to match the device for which the node will be created.\n"
118 /* look for the 'dev' file */
119 attr = sysfs_get_classdev_attr(class_dev, "dev");
121 printf("device '%s' has major:minor %s", class_dev->path, attr->value);
123 /* open sysfs class device directory and print all attributes */
124 printf(" looking at class device '%s':\n", class_dev->path);
125 printf(" SUBSYSTEM==\"%s\"\n", class_dev->classname);
127 attr_list = sysfs_get_classdev_attributes(class_dev);
128 if (attr_list == NULL) {
129 fprintf(stderr, "couldn't open class device directory\n");
133 print_all_attributes(attr_list);
135 /* get the device link (if parent exists look here) */
136 class_dev_parent = sysfs_get_classdev_parent(class_dev);
137 if (class_dev_parent != NULL)
138 sysfs_dev = sysfs_get_classdev_device(class_dev_parent);
140 sysfs_dev = sysfs_get_classdev_device(class_dev);
142 if (sysfs_dev != NULL)
143 printf("follow the \"device\"-link to the physical device:\n");
145 /* look the device chain upwards */
146 while (sysfs_dev != NULL) {
147 printf(" looking at the device chain at '%s':\n", sysfs_dev->path);
148 printf(" BUS==\"%s\"\n", sysfs_dev->bus);
149 printf(" ID==\"%s\"\n", sysfs_dev->bus_id);
150 printf(" DRIVER==\"%s\"\n", sysfs_dev->driver_name);
152 attr_list = sysfs_get_device_attributes(sysfs_dev);
153 if (attr_list != NULL)
154 print_all_attributes(attr_list);
158 sysfs_dev = sysfs_get_device_parent(sysfs_dev);
159 if (sysfs_dev == NULL)
164 sysfs_close_class_device(class_dev);
168 static void dump_names(void) {
169 LIST_HEAD(name_list);
170 struct name_entry *name_loop;
171 struct name_entry *tmp_loop;
173 udev_db_get_all_entries(&name_list);
174 list_for_each_entry_safe(name_loop, tmp_loop, &name_list, node) {
175 struct udevice udev_db;
177 udev_init_device(&udev_db, NULL, NULL, NULL);
178 if (udev_db_get_device(&udev_db, name_loop->name) == 0) {
179 printf("%s=%s/%s\n", udev_db.devpath, udev_root, udev_db.name);
182 udev_cleanup_device(&udev_db);
186 int main(int argc, char *argv[], char *envp[])
188 static const char short_options[] = "adn:p:q:rVh";
200 } query = QUERY_NONE;
201 char path[PATH_SIZE] = "";
202 char name[PATH_SIZE] = "";
203 char temp[PATH_SIZE];
204 struct name_entry *name_loop;
208 logging_init("udevinfo");
211 udev_init_device(&udev, NULL, NULL, NULL);
213 /* get command line options */
215 option = getopt(argc, argv, short_options);
219 dbg("option '%c'", option);
222 dbg("udev name: %s\n", optarg);
223 strlcpy(name, optarg, sizeof(name));
227 dbg("udev path: %s\n", optarg);
228 strlcpy(path, optarg, sizeof(path));
232 dbg("udev query: %s\n", optarg);
234 if (strcmp(optarg, "name") == 0) {
239 if (strcmp(optarg, "symlink") == 0) {
240 query = QUERY_SYMLINK;
244 if (strcmp(optarg, "path") == 0) {
249 if (strcmp(optarg, "env") == 0) {
254 if (strcmp(optarg, "all") == 0) {
259 fprintf(stderr, "unknown query type\n");
276 printf("udevinfo, version %s\n", UDEV_VERSION);
287 /* process options */
288 if (query != QUERY_NONE) {
289 if (path[0] != '\0') {
290 /* remove sysfs_path if given */
291 if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
292 pos = path + strlen(sysfs_path);
294 if (path[0] != '/') {
295 /* prepend '/' if missing */
297 strlcpy(temp, path, sizeof(temp));
303 retval = udev_db_get_device(&udev, pos);
305 fprintf(stderr, "no record for '%s' in database\n", pos);
311 if (name[0] != '\0') {
312 char devpath[PATH_SIZE];
315 /* remove udev_root if given */
316 len = strlen(udev_root);
317 if (strncmp(name, udev_root, len) == 0) {
322 retval = udev_db_search_name(devpath, sizeof(devpath), pos);
324 fprintf(stderr, "device not found in database\n");
327 udev_db_get_device(&udev, devpath);
331 fprintf(stderr, "query needs device path(-p) or node name(-n) specified\n");
339 printf("%s/%s\n", udev_root, udev.name);
341 printf("%s\n", udev.name);
344 if (list_empty(&udev.symlink_list))
347 list_for_each_entry(name_loop, &udev.symlink_list, node)
348 printf("%s/%s ", udev_root, name_loop->name);
350 list_for_each_entry(name_loop, &udev.symlink_list, node)
351 printf("%s ", name_loop->name);
355 printf("%s\n", udev.devpath);
358 list_for_each_entry(name_loop, &udev.env_list, node)
359 printf("%s\n", name_loop->name);
370 if (path[0] == '\0') {
371 fprintf(stderr, "attribute walk on device chain needs path(-p) specified\n");
375 if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) {
376 /* prepend sysfs mountpoint if not given */
377 snprintf(temp, sizeof(temp), "%s%s", sysfs_path, path);
378 temp[sizeof(temp)-1] = '\0';
379 strlcpy(path, temp, sizeof(temp));
381 print_device_chain(path);
387 printf("%s\n", udev_root);
392 fprintf(stderr, "Usage: udevinfo [-anpqrVh]\n"
393 " -q TYPE query database for the specified value:\n"
394 " 'name' name of device node\n"
395 " 'symlink' pointing to node\n"
396 " 'path' sysfs device path\n"
397 " 'env' the device related imported environment\n"
398 " 'all' all values\n"
400 " -p PATH sysfs device path used for query or chain\n"
401 " -n NAME node/symlink name used for query\n"
403 " -r print udev root\n"
404 " -a print all SYSFS_attributes along the device chain\n"
405 " -d print the relationship of devpath and the node name for all\n"
406 " devices available in the database\n"
407 " -V print udev version\n"
408 " -h print this help text\n"
412 udev_cleanup_device(&udev);