2 * udevinfo.c - fetches stored device information or sysfs attributes
4 * Copyright (C) 2004-2005 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 void 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);
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(" KERNEL==\"%s\"\n", class_dev->name);
126 printf(" SUBSYSTEM==\"%s\"\n", class_dev->classname);
128 attr_list = sysfs_get_classdev_attributes(class_dev);
129 if (attr_list == NULL) {
130 fprintf(stderr, "couldn't open class device directory\n");
134 print_all_attributes(attr_list);
136 /* get the device link (if parent exists look here) */
137 class_dev_parent = sysfs_get_classdev_parent(class_dev);
138 if (class_dev_parent != NULL)
139 sysfs_dev = sysfs_get_classdev_device(class_dev_parent);
141 sysfs_dev = sysfs_get_classdev_device(class_dev);
143 if (sysfs_dev != NULL)
144 printf("follow the \"device\"-link to the physical device:\n");
146 /* look the device chain upwards */
147 while (sysfs_dev != NULL) {
148 printf(" looking at the device chain at '%s':\n", sysfs_dev->path);
149 printf(" BUS==\"%s\"\n", sysfs_dev->bus);
150 printf(" ID==\"%s\"\n", sysfs_dev->bus_id);
151 printf(" DRIVER==\"%s\"\n", sysfs_dev->driver_name);
153 attr_list = sysfs_get_device_attributes(sysfs_dev);
154 if (attr_list != NULL)
155 print_all_attributes(attr_list);
159 sysfs_dev = sysfs_get_device_parent(sysfs_dev);
160 if (sysfs_dev == NULL)
165 sysfs_close_class_device(class_dev);
169 static void dump_name_devpath(struct udevice *udev) {
170 printf("%s=%s/%s\n", udev->devpath, udev_root, udev->name);
173 static void dump_record(struct udevice *udev) {
178 static void dump_db(void fnct(struct udevice *udev)) {
179 LIST_HEAD(name_list);
180 struct name_entry *name_loop;
182 udev_db_get_all_entries(&name_list);
183 list_for_each_entry(name_loop, &name_list, node) {
184 struct udevice udev_db;
186 udev_init_device(&udev_db, NULL, NULL, NULL);
187 if (udev_db_get_device(&udev_db, name_loop->name) == 0)
189 udev_cleanup_device(&udev_db);
191 name_list_cleanup(&name_list);
194 static void print_help(void)
196 fprintf(stderr, "Usage: udevinfo [-anpqrVh]\n"
197 " -q TYPE query database for the specified value:\n"
198 " 'name' name of device node\n"
199 " 'symlink' pointing to node\n"
200 " 'path' sysfs device path\n"
201 " 'env' the device related imported environment\n"
202 " 'all' all values\n"
204 " -p PATH sysfs device path used for query or chain\n"
205 " -n NAME node/symlink name used for query\n"
207 " -r print udev root\n"
208 " -a print all SYSFS_attributes along the device chain\n"
209 " -d print the relationship of devpath and the node name for all\n"
210 " -e print the content of the udev database\n"
211 " -V print udev version\n"
212 " -h print this help text\n"
216 int main(int argc, char *argv[], char *envp[])
218 static const char short_options[] = "aden:p:q:rVh";
226 ACTION_ATTRIBUTE_WALK,
228 } action = ACTION_NONE;
237 } query = QUERY_NONE;
239 char path[PATH_SIZE] = "";
240 char name[PATH_SIZE] = "";
241 char temp[PATH_SIZE];
242 struct name_entry *name_loop;
246 logging_init("udevinfo");
249 udev_init_device(&udev, NULL, NULL, NULL);
251 /* get command line options */
253 option = getopt(argc, argv, short_options);
257 dbg("option '%c'", option);
260 dbg("udev name: %s\n", optarg);
261 strlcpy(name, optarg, sizeof(name));
264 dbg("udev path: %s\n", optarg);
265 strlcpy(path, optarg, sizeof(path));
268 dbg("udev query: %s\n", optarg);
269 action = ACTION_QUERY;
270 if (strcmp(optarg, "name") == 0) {
274 if (strcmp(optarg, "symlink") == 0) {
275 query = QUERY_SYMLINK;
278 if (strcmp(optarg, "path") == 0) {
282 if (strcmp(optarg, "env") == 0) {
286 if (strcmp(optarg, "all") == 0) {
290 fprintf(stderr, "unknown query type\n");
294 if (action == ACTION_NONE)
295 action = ACTION_ROOT;
299 action = ACTION_ATTRIBUTE_WALK;
302 dump_db(dump_name_devpath);
305 dump_db(dump_record);
308 printf("udevinfo, version %s\n", UDEV_VERSION);
321 /* need devpath or node/symlink name for query */
322 if (path[0] != '\0') {
323 /* remove sysfs_path if given */
324 if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
325 pos = path + strlen(sysfs_path);
327 if (path[0] != '/') {
328 /* prepend '/' if missing */
330 strlcpy(temp, path, sizeof(temp));
336 retval = udev_db_get_device(&udev, pos);
338 fprintf(stderr, "no record for '%s' in database\n", pos);
342 } else if (name[0] != '\0') {
343 char devpath[PATH_SIZE];
346 /* remove udev_root if given */
347 len = strlen(udev_root);
348 if (strncmp(name, udev_root, len) == 0) {
353 retval = udev_db_lookup_name(pos, devpath, sizeof(devpath));
355 fprintf(stderr, "no record for '%s' in database\n", pos);
359 udev_db_get_device(&udev, devpath);
361 fprintf(stderr, "query needs device path(-p) or node name(-n) specified\n");
369 printf("%s/%s\n", udev_root, udev.name);
371 printf("%s\n", udev.name);
374 if (list_empty(&udev.symlink_list))
377 list_for_each_entry(name_loop, &udev.symlink_list, node)
378 printf("%s/%s ", udev_root, name_loop->name);
380 list_for_each_entry(name_loop, &udev.symlink_list, node)
381 printf("%s ", name_loop->name);
385 printf("%s\n", udev.devpath);
388 list_for_each_entry(name_loop, &udev.env_list, node)
389 printf("%s\n", name_loop->name);
399 case ACTION_ATTRIBUTE_WALK:
400 if (path[0] == '\0') {
401 fprintf(stderr, "attribute walk on device chain needs path(-p) specified\n");
405 if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) {
406 /* prepend sysfs mountpoint if not given */
407 snprintf(temp, sizeof(temp), "%s%s", sysfs_path, path);
408 temp[sizeof(temp)-1] = '\0';
409 strlcpy(path, temp, sizeof(temp));
411 print_device_chain(path);
415 printf("%s\n", udev_root);
424 udev_cleanup_device(&udev);