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);
91 list_for_each_entry(name_loop, &udev->env_list, node)
92 printf("E: %s\n", name_loop->name);
97 static int print_device_chain(const char *path)
99 struct sysfs_class_device *class_dev;
100 struct sysfs_class_device *class_dev_parent;
101 struct sysfs_attribute *attr;
102 struct sysfs_device *sysfs_dev;
103 struct dlist *attr_list;
106 /* get the class dev */
107 class_dev = sysfs_open_class_device_path(path);
108 if (class_dev == NULL) {
109 fprintf(stderr, "couldn't get the class device\n");
113 printf("\nudevinfo starts with the device the node belongs to and then walks up the\n"
114 "device chain, to print for every device found, all possibly useful attributes\n"
115 "in the udev key format.\n"
116 "Only attributes within one device section may be used together in one rule,\n"
117 "to match the device for which the node will be created.\n"
120 /* look for the 'dev' file */
121 attr = sysfs_get_classdev_attr(class_dev, "dev");
123 printf("device '%s' has major:minor %s", class_dev->path, attr->value);
125 /* open sysfs class device directory and print all attributes */
126 printf(" looking at class device '%s':\n", class_dev->path);
127 printf(" SUBSYSTEM==\"%s\"\n", class_dev->classname);
129 attr_list = sysfs_get_classdev_attributes(class_dev);
130 if (attr_list == NULL) {
131 fprintf(stderr, "couldn't open class device directory\n");
135 print_all_attributes(attr_list);
137 /* get the device link (if parent exists look here) */
138 class_dev_parent = sysfs_get_classdev_parent(class_dev);
139 if (class_dev_parent != NULL)
140 sysfs_dev = sysfs_get_classdev_device(class_dev_parent);
142 sysfs_dev = sysfs_get_classdev_device(class_dev);
144 if (sysfs_dev != NULL)
145 printf("follow the \"device\"-link to the physical device:\n");
147 /* look the device chain upwards */
148 while (sysfs_dev != NULL) {
149 printf(" looking at the device chain at '%s':\n", sysfs_dev->path);
150 printf(" BUS==\"%s\"\n", sysfs_dev->bus);
151 printf(" ID==\"%s\"\n", sysfs_dev->bus_id);
152 printf(" DRIVER==\"%s\"\n", sysfs_dev->driver_name);
154 attr_list = sysfs_get_device_attributes(sysfs_dev);
155 if (attr_list != NULL)
156 print_all_attributes(attr_list);
160 sysfs_dev = sysfs_get_device_parent(sysfs_dev);
161 if (sysfs_dev == NULL)
166 sysfs_close_class_device(class_dev);
170 static void dump_names(void) {
171 LIST_HEAD(name_list);
172 struct name_entry *name_loop;
173 struct name_entry *tmp_loop;
175 udev_db_get_all_entries(&name_list);
176 list_for_each_entry_safe(name_loop, tmp_loop, &name_list, node) {
177 struct udevice udev_db;
179 udev_init_device(&udev_db, NULL, NULL, NULL);
180 if (udev_db_get_device(&udev_db, name_loop->name) == 0) {
181 printf("%s=%s/%s\n", udev_db.devpath, udev_root, udev_db.name);
184 udev_cleanup_device(&udev_db);
188 int main(int argc, char *argv[], char *envp[])
190 static const char short_options[] = "adn:p:q:rVh";
202 } query = QUERY_NONE;
203 char path[PATH_SIZE] = "";
204 char name[PATH_SIZE] = "";
205 char temp[PATH_SIZE];
206 struct name_entry *name_loop;
210 logging_init("udevinfo");
213 udev_init_device(&udev, NULL, NULL, NULL);
215 /* get command line options */
217 option = getopt(argc, argv, short_options);
221 dbg("option '%c'", option);
224 dbg("udev name: %s\n", optarg);
225 strlcpy(name, optarg, sizeof(name));
229 dbg("udev path: %s\n", optarg);
230 strlcpy(path, optarg, sizeof(path));
234 dbg("udev query: %s\n", optarg);
236 if (strcmp(optarg, "name") == 0) {
241 if (strcmp(optarg, "symlink") == 0) {
242 query = QUERY_SYMLINK;
246 if (strcmp(optarg, "path") == 0) {
251 if (strcmp(optarg, "env") == 0) {
256 if (strcmp(optarg, "all") == 0) {
261 fprintf(stderr, "unknown query type\n");
278 printf("udevinfo, version %s\n", UDEV_VERSION);
289 /* process options */
290 if (query != QUERY_NONE) {
291 if (path[0] != '\0') {
292 /* remove sysfs_path if given */
293 if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
294 pos = path + strlen(sysfs_path);
296 if (path[0] != '/') {
297 /* prepend '/' if missing */
299 strlcpy(temp, path, sizeof(temp));
305 retval = udev_db_get_device(&udev, pos);
307 fprintf(stderr, "no record for '%s' in database\n", pos);
313 if (name[0] != '\0') {
314 char devpath[PATH_SIZE];
317 /* remove udev_root if given */
318 len = strlen(udev_root);
319 if (strncmp(name, udev_root, len) == 0) {
324 retval = udev_db_search_name(devpath, sizeof(devpath), pos);
326 fprintf(stderr, "no record for '%s' in database\n", pos);
329 udev_db_get_device(&udev, devpath);
333 fprintf(stderr, "query needs device path(-p) or node name(-n) specified\n");
341 printf("%s/%s\n", udev_root, udev.name);
343 printf("%s\n", udev.name);
346 if (list_empty(&udev.symlink_list))
349 list_for_each_entry(name_loop, &udev.symlink_list, node)
350 printf("%s/%s ", udev_root, name_loop->name);
352 list_for_each_entry(name_loop, &udev.symlink_list, node)
353 printf("%s ", name_loop->name);
357 printf("%s\n", udev.devpath);
360 list_for_each_entry(name_loop, &udev.env_list, node)
361 printf("%s\n", name_loop->name);
372 if (path[0] == '\0') {
373 fprintf(stderr, "attribute walk on device chain needs path(-p) specified\n");
377 if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) {
378 /* prepend sysfs mountpoint if not given */
379 snprintf(temp, sizeof(temp), "%s%s", sysfs_path, path);
380 temp[sizeof(temp)-1] = '\0';
381 strlcpy(path, temp, sizeof(temp));
383 print_device_chain(path);
389 printf("%s\n", udev_root);
394 fprintf(stderr, "Usage: udevinfo [-anpqrVh]\n"
395 " -q TYPE query database for the specified value:\n"
396 " 'name' name of device node\n"
397 " 'symlink' pointing to node\n"
398 " 'path' sysfs device path\n"
399 " 'env' the device related imported environment\n"
400 " 'all' all values\n"
402 " -p PATH sysfs device path used for query or chain\n"
403 " -n NAME node/symlink name used for query\n"
405 " -r print udev root\n"
406 " -a print all SYSFS_attributes along the device chain\n"
407 " -d print the relationship of devpath and the node name for all\n"
408 " devices available in the database\n"
409 " -V print udev version\n"
410 " -h print this help text\n"
414 udev_cleanup_device(&udev);