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 export_name_devpath(struct udevice *udev) {
170 printf("%s=%s/%s\n", udev->devpath, udev_root, udev->name);
173 static void export_record(struct udevice *udev) {
178 static void export_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 prepend to query result or print udev_root\n"
208 " -a print all SYSFS_attributes along the device chain\n"
209 " -e export the content of the udev database\n"
210 " -V print udev version\n"
211 " -h print this help text\n"
215 int main(int argc, char *argv[], char *envp[])
217 static const char short_options[] = "aden:p:q:rVh";
225 ACTION_ATTRIBUTE_WALK,
227 } action = ACTION_NONE;
236 } query = QUERY_NONE;
238 char path[PATH_SIZE] = "";
239 char name[PATH_SIZE] = "";
240 char temp[PATH_SIZE];
241 struct name_entry *name_loop;
245 logging_init("udevinfo");
248 udev_init_device(&udev, NULL, NULL, NULL);
250 /* get command line options */
252 option = getopt(argc, argv, short_options);
256 dbg("option '%c'", option);
259 dbg("udev name: %s\n", optarg);
260 strlcpy(name, optarg, sizeof(name));
263 dbg("udev path: %s\n", optarg);
264 strlcpy(path, optarg, sizeof(path));
267 dbg("udev query: %s\n", optarg);
268 action = ACTION_QUERY;
269 if (strcmp(optarg, "name") == 0) {
273 if (strcmp(optarg, "symlink") == 0) {
274 query = QUERY_SYMLINK;
277 if (strcmp(optarg, "path") == 0) {
281 if (strcmp(optarg, "env") == 0) {
285 if (strcmp(optarg, "all") == 0) {
289 fprintf(stderr, "unknown query type\n");
293 if (action == ACTION_NONE)
294 action = ACTION_ROOT;
298 action = ACTION_ATTRIBUTE_WALK;
301 export_db(export_name_devpath);
304 export_db(export_record);
307 printf("udevinfo, version %s\n", UDEV_VERSION);
320 /* need devpath or node/symlink name for query */
321 if (path[0] != '\0') {
322 /* remove sysfs_path if given */
323 if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
324 pos = path + strlen(sysfs_path);
326 if (path[0] != '/') {
327 /* prepend '/' if missing */
329 strlcpy(temp, path, sizeof(temp));
335 retval = udev_db_get_device(&udev, pos);
337 fprintf(stderr, "no record for '%s' in database\n", pos);
341 } else if (name[0] != '\0') {
342 char devpath[PATH_SIZE];
345 /* remove udev_root if given */
346 len = strlen(udev_root);
347 if (strncmp(name, udev_root, len) == 0) {
352 retval = udev_db_lookup_name(pos, devpath, sizeof(devpath));
354 fprintf(stderr, "no record for '%s' in database\n", pos);
358 udev_db_get_device(&udev, devpath);
360 fprintf(stderr, "query needs device path(-p) or node name(-n) specified\n");
368 printf("%s/%s\n", udev_root, udev.name);
370 printf("%s\n", udev.name);
373 if (list_empty(&udev.symlink_list))
376 list_for_each_entry(name_loop, &udev.symlink_list, node)
377 printf("%s/%s ", udev_root, name_loop->name);
379 list_for_each_entry(name_loop, &udev.symlink_list, node)
380 printf("%s ", name_loop->name);
384 printf("%s\n", udev.devpath);
387 list_for_each_entry(name_loop, &udev.env_list, node)
388 printf("%s\n", name_loop->name);
398 case ACTION_ATTRIBUTE_WALK:
399 if (path[0] == '\0') {
400 fprintf(stderr, "attribute walk on device chain needs path(-p) specified\n");
404 if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) {
405 /* prepend sysfs mountpoint if not given */
406 snprintf(temp, sizeof(temp), "%s%s", sysfs_path, path);
407 temp[sizeof(temp)-1] = '\0';
408 strlcpy(path, temp, sizeof(temp));
410 print_device_chain(path);
414 printf("%s\n", udev_root);
423 udev_cleanup_device(&udev);