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 printf("L: %i\n", udev->link_priority);
148 list_for_each_entry(name_loop, &udev->symlink_list, node)
149 printf("S: %s\n", name_loop->name);
150 list_for_each_entry(name_loop, &udev->env_list, node)
151 printf("E: %s\n", name_loop->name);
154 static void export_db(void) {
155 LIST_HEAD(name_list);
156 struct name_entry *name_loop;
158 udev_db_get_all_entries(&name_list);
159 list_for_each_entry(name_loop, &name_list, node) {
160 struct udevice *udev_db;
162 udev_db = udev_device_init(NULL);
165 if (udev_db_get_device(udev_db, name_loop->name) == 0)
166 print_record(udev_db);
168 udev_device_cleanup(udev_db);
170 name_list_cleanup(&name_list);
173 static int lookup_device_by_name(struct udevice *udev, const char *name)
175 LIST_HEAD(name_list);
176 struct name_entry *device;
179 if (udev_db_get_devices_by_name(name, &name_list) <= 0)
182 /* select the device that matches the dev_t of name */
183 list_for_each_entry(device, &name_list, node) {
184 char filename[PATH_SIZE];
187 udev_device_init(udev);
188 if (udev_db_get_device(udev, device->name) != 0)
190 info("found db entry '%s'", device->name);
192 strlcpy(filename, udev_root, sizeof(filename));
193 strlcat(filename, "/", sizeof(filename));
194 strlcat(filename, name, sizeof(filename));
195 if (stat(filename, &statbuf) != 0)
197 if (statbuf.st_rdev == udev->devt) {
198 info("found '%s', dev_t matches", udev->name);
204 name_list_cleanup(&name_list);
208 int main(int argc, char *argv[], char *envp[])
211 struct udevice *udev;
214 static const struct option options[] = {
215 { "name", 1, NULL, 'n' },
216 { "path", 1, NULL, 'p' },
217 { "query", 1, NULL, 'q' },
218 { "attribute-walk", 0, NULL, 'a' },
219 { "export-db", 0, NULL, 'e' },
220 { "root", 0, NULL, 'r' },
221 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
222 { "help", 0, NULL, 'h' },
229 ACTION_ATTRIBUTE_WALK,
231 } action = ACTION_NONE;
240 } query = QUERY_NONE;
242 char path[PATH_SIZE] = "";
243 char name[PATH_SIZE] = "";
244 struct name_entry *name_loop;
247 logging_init("udevinfo");
251 udev = udev_device_init(NULL);
257 /* get command line options */
259 option = getopt_long(argc, argv, "aen:p:q:rVh", options, NULL);
263 dbg("option '%c'", option);
266 /* remove /dev if given */
267 if (strncmp(optarg, udev_root, strlen(udev_root)) == 0)
268 strlcpy(name, &optarg[strlen(udev_root)+1], sizeof(name));
270 strlcpy(name, optarg, sizeof(name));
271 dbg("name: %s\n", name);
274 /* remove /sys if given */
275 if (strncmp(optarg, sysfs_path, strlen(sysfs_path)) == 0)
276 strlcpy(path, &optarg[strlen(sysfs_path)], sizeof(path));
278 strlcpy(path, optarg, sizeof(path));
279 dbg("path: %s\n", path);
282 dbg("udev query: %s\n", optarg);
283 action = ACTION_QUERY;
284 if (strcmp(optarg, "name") == 0) {
288 if (strcmp(optarg, "symlink") == 0) {
289 query = QUERY_SYMLINK;
292 if (strcmp(optarg, "path") == 0) {
296 if (strcmp(optarg, "env") == 0) {
300 if (strcmp(optarg, "all") == 0) {
304 fprintf(stderr, "unknown query type\n");
308 if (action == ACTION_NONE)
309 action = ACTION_ROOT;
313 action = ACTION_ATTRIBUTE_WALK;
319 printf("%s\n", UDEV_VERSION);
322 printf("udevinfo, version %s\n", UDEV_VERSION);
325 printf("Usage: udevinfo OPTIONS\n"
326 " --query=<type> query database for the specified value:\n"
327 " name name of device node\n"
328 " symlink pointing to node\n"
329 " path sysfs device path\n"
330 " env the device related imported environment\n"
333 " --path=<devpath> sysfs device path used for query or chain\n"
334 " --name=<name> node or symlink name used for query\n"
336 " --root prepend to query result or print udev_root\n"
337 " --attribute-walk print all SYSFS_attributes along the device chain\n"
338 " --export-db export the content of the udev database\n"
339 " --help print this text\n"
350 /* needs devpath or node/symlink name for query */
351 if (path[0] != '\0') {
352 if (udev_db_get_device(udev, path) != 0) {
353 fprintf(stderr, "no record for '%s' in database\n", path);
357 } else if (name[0] != '\0') {
358 if (lookup_device_by_name(udev, name) != 0) {
359 fprintf(stderr, "node name not found\n");
364 fprintf(stderr, "query needs --path or node --name specified\n");
372 printf("%s/%s\n", udev_root, udev->name);
374 printf("%s\n", udev->name);
377 if (list_empty(&udev->symlink_list))
380 list_for_each_entry(name_loop, &udev->symlink_list, node)
381 printf("%s/%s ", udev_root, name_loop->name);
383 list_for_each_entry(name_loop, &udev->symlink_list, node)
384 printf("%s ", name_loop->name);
388 printf("%s\n", udev->dev->devpath);
391 list_for_each_entry(name_loop, &udev->env_list, node)
392 printf("%s\n", name_loop->name);
398 fprintf(stderr, "unknown query type\n");
402 case ACTION_ATTRIBUTE_WALK:
403 if (path[0] != '\0') {
404 if (print_device_chain(path) != 0) {
405 fprintf(stderr, "device not found\n");
409 } else if (name[0] != '\0') {
410 if (lookup_device_by_name(udev, name) != 0) {
411 fprintf(stderr, "node name not found\n");
415 if (print_device_chain(udev->dev->devpath) != 0) {
416 fprintf(stderr, "device not found\n");
421 fprintf(stderr, "attribute walk needs --path or node --name specified\n");
427 printf("%s\n", udev_root);
430 fprintf(stderr, "missing option\n");
436 udev_device_cleanup(udev);