2 * Copyright (C) 2004-2006 Kay Sievers <kay.sievers@vrfy.org>
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation version 2 of the License.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
30 #include <sys/types.h>
36 void log_message (int priority, const char *format, ...)
40 if (priority > udev_log_priority)
43 va_start(args, format);
44 vsyslog(priority, format, args);
49 static void print_all_attributes(const char *devpath, const char *key)
55 strlcpy(path, sysfs_path, sizeof(path));
56 strlcat(path, devpath, sizeof(path));
60 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
62 char filename[PATH_SIZE];
64 char value[NAME_SIZE];
67 if (dent->d_name[0] == '.')
70 strlcpy(filename, path, sizeof(filename));
71 strlcat(filename, "/", sizeof(filename));
72 strlcat(filename, dent->d_name, sizeof(filename));
73 if (lstat(filename, &statbuf) != 0)
75 if (S_ISLNK(statbuf.st_mode))
78 attr_value = sysfs_attr_get_value(devpath, dent->d_name);
79 if (attr_value == NULL)
81 len = strlcpy(value, attr_value, sizeof(value));
82 dbg("attr '%s'='%s'(%zi)", dent->d_name, value, len);
84 /* remove trailing newlines */
85 while (len && value[len-1] == '\n')
88 /* skip nonprintable attributes */
89 while (len && isprint(value[len-1]))
92 dbg("attribute value of '%s' non-printable, skip", dent->d_name);
96 replace_untrusted_chars(value);
97 printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
103 static int print_device_chain(const char *devpath)
105 struct sysfs_device *dev;
107 dev = sysfs_device_get(devpath);
112 "Udevinfo starts with the device specified by the devpath and then\n"
113 "walks up the chain of parent devices. It prints for every device\n"
114 "found, all possible attributes in the udev rules key format.\n"
115 "A rule to match, can be composed by the attributes of the device\n"
116 "and the attributes from one single parent device.\n"
119 printf(" looking at device '%s':\n", dev->devpath);
120 printf(" KERNEL==\"%s\"\n", dev->kernel);
121 printf(" SUBSYSTEM==\"%s\"\n", dev->subsystem);
122 printf(" DRIVER==\"%s\"\n", dev->driver);
123 print_all_attributes(dev->devpath, "ATTR");
125 /* walk up the chain of devices */
127 dev = sysfs_device_get_parent(dev);
130 printf(" looking at parent device '%s':\n", dev->devpath);
131 printf(" KERNELS==\"%s\"\n", dev->kernel);
132 printf(" SUBSYSTEMS==\"%s\"\n", dev->subsystem);
133 printf(" DRIVERS==\"%s\"\n", dev->driver);
135 print_all_attributes(dev->devpath, "ATTRS");
141 static void print_record(struct udevice *udev)
143 struct name_entry *name_loop;
145 printf("P: %s\n", udev->dev->devpath);
146 printf("N: %s\n", udev->name);
147 list_for_each_entry(name_loop, &udev->symlink_list, node)
148 printf("S: %s\n", name_loop->name);
149 list_for_each_entry(name_loop, &udev->env_list, node)
150 printf("E: %s\n", name_loop->name);
153 static void export_name_devpath(struct udevice *udev) {
154 printf("%s=%s/%s\n", udev->dev->devpath, udev_root, udev->name);
157 static void export_record(struct udevice *udev) {
162 static void export_db(void fnct(struct udevice *udev)) {
163 LIST_HEAD(name_list);
164 struct name_entry *name_loop;
166 udev_db_get_all_entries(&name_list);
167 list_for_each_entry(name_loop, &name_list, node) {
168 struct udevice *udev_db;
170 udev_db = udev_device_init(NULL);
173 if (udev_db_get_device(udev_db, name_loop->name) == 0)
175 udev_device_cleanup(udev_db);
177 name_list_cleanup(&name_list);
180 static int lookup_device_by_name(struct udevice *udev, const char *name)
182 LIST_HEAD(name_list);
183 struct name_entry *device;
186 if (udev_db_get_devices_by_name(name, &name_list) <= 0)
189 /* select the device that matches the dev_t of name */
190 list_for_each_entry(device, &name_list, node) {
191 char filename[PATH_SIZE];
194 udev_device_init(udev);
195 if (udev_db_get_device(udev, device->name) != 0)
197 info("found db entry '%s'", device->name);
199 strlcpy(filename, udev_root, sizeof(filename));
200 strlcat(filename, "/", sizeof(filename));
201 strlcat(filename, name, sizeof(filename));
202 if (stat(filename, &statbuf) != 0)
204 if (statbuf.st_rdev == udev->devt) {
205 info("found '%s', dev_t matches", udev->name);
211 name_list_cleanup(&name_list);
215 int main(int argc, char *argv[], char *envp[])
218 struct udevice *udev;
221 static const struct option options[] = {
222 { "name", 1, NULL, 'n' },
223 { "path", 1, NULL, 'p' },
224 { "query", 1, NULL, 'q' },
225 { "attribute-walk", 0, NULL, 'a' },
226 { "export-db", 0, NULL, 'e' },
227 { "root", 0, NULL, 'r' },
228 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
229 { "help", 0, NULL, 'h' },
236 ACTION_ATTRIBUTE_WALK,
238 } action = ACTION_NONE;
247 } query = QUERY_NONE;
249 char path[PATH_SIZE] = "";
250 char name[PATH_SIZE] = "";
251 struct name_entry *name_loop;
254 logging_init("udevinfo");
258 udev = udev_device_init(NULL);
264 /* get command line options */
266 option = getopt_long(argc, argv, "aden:p:q:rVh", options, NULL);
270 dbg("option '%c'", option);
273 /* remove /dev if given */
274 if (strncmp(optarg, udev_root, strlen(udev_root)) == 0)
275 strlcpy(name, &optarg[strlen(udev_root)+1], sizeof(name));
277 strlcpy(name, optarg, sizeof(name));
278 dbg("name: %s\n", name);
281 /* remove /sys if given */
282 if (strncmp(optarg, sysfs_path, strlen(sysfs_path)) == 0)
283 strlcpy(path, &optarg[strlen(sysfs_path)], sizeof(path));
285 strlcpy(path, optarg, sizeof(path));
286 dbg("path: %s\n", path);
289 dbg("udev query: %s\n", optarg);
290 action = ACTION_QUERY;
291 if (strcmp(optarg, "name") == 0) {
295 if (strcmp(optarg, "symlink") == 0) {
296 query = QUERY_SYMLINK;
299 if (strcmp(optarg, "path") == 0) {
303 if (strcmp(optarg, "env") == 0) {
307 if (strcmp(optarg, "all") == 0) {
311 fprintf(stderr, "unknown query type\n");
315 if (action == ACTION_NONE)
316 action = ACTION_ROOT;
320 action = ACTION_ATTRIBUTE_WALK;
323 export_db(export_name_devpath);
326 export_db(export_record);
329 printf("%s\n", UDEV_VERSION);
332 printf("udevinfo, version %s\n", UDEV_VERSION);
335 printf("Usage: udevinfo OPTIONS\n"
336 " --query=<type> query database for the specified value:\n"
337 " name name of device node\n"
338 " symlink pointing to node\n"
339 " path sysfs device path\n"
340 " env the device related imported environment\n"
343 " --path=<devpath> sysfs device path used for query or chain\n"
344 " --name=<name> node or symlink name used for query\n"
346 " --root prepend to query result or print udev_root\n"
347 " --attribute-walk print all SYSFS_attributes along the device chain\n"
348 " --export-db export the content of the udev database\n"
349 " --help print this text\n"
360 /* needs devpath or node/symlink name for query */
361 if (path[0] != '\0') {
362 if (udev_db_get_device(udev, path) != 0) {
363 fprintf(stderr, "no record for '%s' in database\n", path);
367 } else if (name[0] != '\0') {
368 if (lookup_device_by_name(udev, name) != 0) {
369 fprintf(stderr, "node name not found\n");
374 fprintf(stderr, "query needs --path or node --name specified\n");
382 printf("%s/%s\n", udev_root, udev->name);
384 printf("%s\n", udev->name);
387 if (list_empty(&udev->symlink_list))
390 list_for_each_entry(name_loop, &udev->symlink_list, node)
391 printf("%s/%s ", udev_root, name_loop->name);
393 list_for_each_entry(name_loop, &udev->symlink_list, node)
394 printf("%s ", name_loop->name);
398 printf("%s\n", udev->dev->devpath);
401 list_for_each_entry(name_loop, &udev->env_list, node)
402 printf("%s\n", name_loop->name);
408 fprintf(stderr, "unknown query type\n");
412 case ACTION_ATTRIBUTE_WALK:
413 if (path[0] != '\0') {
414 if (print_device_chain(path) != 0) {
415 fprintf(stderr, "device not found\n");
419 } else if (name[0] != '\0') {
420 if (lookup_device_by_name(udev, name) != 0) {
421 fprintf(stderr, "node name not found\n");
425 if (print_device_chain(udev->dev->devpath) != 0) {
426 fprintf(stderr, "device not found\n");
431 fprintf(stderr, "attribute walk needs --path or node --name specified\n");
437 printf("%s\n", udev_root);
440 fprintf(stderr, "missing option\n");
446 udev_device_cleanup(udev);