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;
174 udev_db_get_all_entries(&name_list);
175 list_for_each_entry(name_loop, &name_list, node) {
176 struct udevice udev_db;
178 udev_init_device(&udev_db, NULL, NULL, NULL);
179 if (udev_db_get_device(&udev_db, name_loop->name) == 0)
180 printf("%s=%s/%s\n", udev_db.devpath, udev_root, udev_db.name);
181 udev_cleanup_device(&udev_db);
183 name_list_cleanup(&name_list);
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_lookup_name(pos, devpath, sizeof(devpath));
324 fprintf(stderr, "no record for '%s' in database\n", pos);
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);