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"
38 void log_message (int priority, const char *format, ...)
42 if (priority > udev_log_priority)
45 va_start(args, format);
46 vsyslog(priority, format, args);
51 static void print_all_attributes(struct dlist *attr_list)
53 struct sysfs_attribute *attr;
54 char value[VALUE_SIZE];
57 dlist_for_each_data(attr_list, attr, struct sysfs_attribute) {
58 if (attr->value == NULL)
60 len = strlcpy(value, attr->value, sizeof(value));
61 if (len >= sizeof(value)) {
62 dbg("attribute value of '%s' too long, skip", attr->name);
66 /* remove trailing newlines */
67 while (len && value[len-1] == '\n')
69 /* skip nonprintable attributes */
70 while (len && isprint(value[len-1]))
73 dbg("attribute value of '%s' non-printable, skip", attr->name);
76 replace_untrusted_chars(value);
77 printf(" SYSFS{%s}==\"%s\"\n", attr->name, value);
82 static void print_record(struct udevice *udev)
84 struct name_entry *name_loop;
86 printf("P: %s\n", udev->devpath);
87 printf("N: %s\n", udev->name);
88 list_for_each_entry(name_loop, &udev->symlink_list, node)
89 printf("S: %s\n", name_loop->name);
90 list_for_each_entry(name_loop, &udev->env_list, node)
91 printf("E: %s\n", name_loop->name);
94 static int print_device_chain(const char *path)
96 struct sysfs_class_device *class_dev;
97 struct sysfs_class_device *class_dev_parent;
98 struct sysfs_attribute *attr;
99 struct sysfs_device *sysfs_dev;
100 struct dlist *attr_list;
103 /* get the class dev */
104 class_dev = sysfs_open_class_device_path(path);
105 if (class_dev == NULL) {
106 fprintf(stderr, "couldn't get the class device\n");
110 printf("\nudevinfo starts with the device the node belongs to and then walks up the\n"
111 "device chain, to print for every device found, all possibly useful attributes\n"
112 "in the udev key format.\n"
113 "Only attributes within one device section may be used together in one rule,\n"
114 "to match the device for which the node will be created.\n"
117 /* look for the 'dev' file */
118 attr = sysfs_get_classdev_attr(class_dev, "dev");
120 printf("device '%s' has major:minor %s", class_dev->path, attr->value);
122 /* open sysfs class device directory and print all attributes */
123 printf(" looking at class device '%s':\n", class_dev->path);
124 printf(" KERNEL==\"%s\"\n", class_dev->name);
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 export_name_devpath(struct udevice *udev) {
169 printf("%s=%s/%s\n", udev->devpath, udev_root, udev->name);
172 static void export_record(struct udevice *udev) {
177 static void export_db(void fnct(struct udevice *udev)) {
178 LIST_HEAD(name_list);
179 struct name_entry *name_loop;
181 udev_db_get_all_entries(&name_list);
182 list_for_each_entry(name_loop, &name_list, node) {
183 struct udevice udev_db;
185 udev_init_device(&udev_db, NULL, NULL, NULL);
186 if (udev_db_get_device(&udev_db, name_loop->name) == 0)
188 udev_cleanup_device(&udev_db);
190 name_list_cleanup(&name_list);
193 static void print_help(void)
195 fprintf(stderr, "Usage: udevinfo [-anpqrVh]\n"
196 " -q TYPE query database for the specified value:\n"
197 " 'name' name of device node\n"
198 " 'symlink' pointing to node\n"
199 " 'path' sysfs device path\n"
200 " 'env' the device related imported environment\n"
201 " 'all' all values\n"
203 " -p PATH sysfs device path used for query or chain\n"
204 " -n NAME node/symlink name used for query\n"
206 " -r prepend to query result or print udev_root\n"
207 " -a print all SYSFS_attributes along the device chain\n"
208 " -e export the content of the udev database\n"
209 " -V print udev version\n"
210 " -h print this help text\n"
214 int main(int argc, char *argv[], char *envp[])
216 static const char short_options[] = "aden:p:q:rVh";
224 ACTION_ATTRIBUTE_WALK,
226 } action = ACTION_NONE;
235 } query = QUERY_NONE;
237 char path[PATH_SIZE] = "";
238 char name[PATH_SIZE] = "";
239 char temp[PATH_SIZE];
240 struct name_entry *name_loop;
244 logging_init("udevinfo");
247 udev_init_device(&udev, NULL, NULL, NULL);
249 /* get command line options */
251 option = getopt(argc, argv, short_options);
255 dbg("option '%c'", option);
258 dbg("udev name: %s\n", optarg);
259 strlcpy(name, optarg, sizeof(name));
262 dbg("udev path: %s\n", optarg);
263 strlcpy(path, optarg, sizeof(path));
266 dbg("udev query: %s\n", optarg);
267 action = ACTION_QUERY;
268 if (strcmp(optarg, "name") == 0) {
272 if (strcmp(optarg, "symlink") == 0) {
273 query = QUERY_SYMLINK;
276 if (strcmp(optarg, "path") == 0) {
280 if (strcmp(optarg, "env") == 0) {
284 if (strcmp(optarg, "all") == 0) {
288 fprintf(stderr, "unknown query type\n");
292 if (action == ACTION_NONE)
293 action = ACTION_ROOT;
297 action = ACTION_ATTRIBUTE_WALK;
300 export_db(export_name_devpath);
303 export_db(export_record);
306 printf("udevinfo, version %s\n", UDEV_VERSION);
319 /* need devpath or node/symlink name for query */
320 if (path[0] != '\0') {
321 /* remove sysfs_path if given */
322 if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
323 pos = path + strlen(sysfs_path);
325 if (path[0] != '/') {
326 /* prepend '/' if missing */
328 strlcpy(temp, path, sizeof(temp));
334 retval = udev_db_get_device(&udev, pos);
336 fprintf(stderr, "no record for '%s' in database\n", pos);
340 } else if (name[0] != '\0') {
341 char devpath[PATH_SIZE];
344 /* remove udev_root if given */
345 len = strlen(udev_root);
346 if (strncmp(name, udev_root, len) == 0) {
351 retval = udev_db_lookup_name(pos, devpath, sizeof(devpath));
353 fprintf(stderr, "no record for '%s' in database\n", pos);
357 udev_db_get_device(&udev, devpath);
359 fprintf(stderr, "query needs device path(-p) or node name(-n) specified\n");
367 printf("%s/%s\n", udev_root, udev.name);
369 printf("%s\n", udev.name);
372 if (list_empty(&udev.symlink_list))
375 list_for_each_entry(name_loop, &udev.symlink_list, node)
376 printf("%s/%s ", udev_root, name_loop->name);
378 list_for_each_entry(name_loop, &udev.symlink_list, node)
379 printf("%s ", name_loop->name);
383 printf("%s\n", udev.devpath);
386 list_for_each_entry(name_loop, &udev.env_list, node)
387 printf("%s\n", name_loop->name);
397 case ACTION_ATTRIBUTE_WALK:
398 if (path[0] == '\0') {
399 fprintf(stderr, "attribute walk on device chain needs path(-p) specified\n");
403 if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) {
404 /* prepend sysfs mountpoint if not given */
405 snprintf(temp, sizeof(temp), "%s%s", sysfs_path, path);
406 temp[sizeof(temp)-1] = '\0';
407 strlcpy(path, temp, sizeof(temp));
409 print_device_chain(path);
413 printf("%s\n", udev_root);
422 udev_cleanup_device(&udev);