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_chars(value, ALLOWED_CHARS_INPUT);
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 if (udev->link_priority != 0)
150 printf("L: %i\n", udev->link_priority);
151 if (udev->partitions != 0)
152 printf("A:%u\n", udev->partitions);
153 if (udev->ignore_remove)
154 printf("R:%u\n", udev->ignore_remove);
155 list_for_each_entry(name_loop, &udev->env_list, node)
156 printf("E: %s\n", name_loop->name);
159 static void export_db(void) {
160 LIST_HEAD(name_list);
161 struct name_entry *name_loop;
163 udev_db_get_all_entries(&name_list);
164 list_for_each_entry(name_loop, &name_list, node) {
165 struct udevice *udev_db;
167 udev_db = udev_device_init(NULL);
170 if (udev_db_get_device(udev_db, name_loop->name) == 0)
171 print_record(udev_db);
173 udev_device_cleanup(udev_db);
175 name_list_cleanup(&name_list);
178 static int lookup_device_by_name(struct udevice *udev, const char *name)
180 LIST_HEAD(name_list);
182 struct name_entry *device;
185 count = udev_db_get_devices_by_name(name, &name_list);
189 info("found %i devices for '%s'", count, name);
191 /* select the device that seems to match */
192 list_for_each_entry(device, &name_list, node) {
193 char filename[PATH_SIZE];
196 udev_device_init(udev);
197 if (udev_db_get_device(udev, device->name) != 0)
199 info("found db entry '%s'", device->name);
201 /* make sure, we don't get a link of a differnt device */
202 strlcpy(filename, udev_root, sizeof(filename));
203 strlcat(filename, "/", sizeof(filename));
204 strlcat(filename, name, sizeof(filename));
205 if (stat(filename, &statbuf) != 0)
207 if (major(udev->devt) > 0 && udev->devt != statbuf.st_rdev) {
208 info("skip '%s', dev_t doesn't match", udev->name);
215 name_list_cleanup(&name_list);
219 int main(int argc, char *argv[], char *envp[])
222 struct udevice *udev;
225 static const struct option options[] = {
226 { "name", 1, NULL, 'n' },
227 { "path", 1, NULL, 'p' },
228 { "query", 1, NULL, 'q' },
229 { "attribute-walk", 0, NULL, 'a' },
230 { "export-db", 0, NULL, 'e' },
231 { "root", 0, NULL, 'r' },
232 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
233 { "help", 0, NULL, 'h' },
240 ACTION_ATTRIBUTE_WALK,
242 } action = ACTION_NONE;
251 } query = QUERY_NONE;
253 char path[PATH_SIZE] = "";
254 char name[PATH_SIZE] = "";
255 struct name_entry *name_loop;
258 logging_init("udevinfo");
262 udev = udev_device_init(NULL);
268 /* get command line options */
270 option = getopt_long(argc, argv, "aen:p:q:rVh", options, NULL);
274 dbg("option '%c'", option);
277 /* remove /dev if given */
278 if (strncmp(optarg, udev_root, strlen(udev_root)) == 0)
279 strlcpy(name, &optarg[strlen(udev_root)+1], sizeof(name));
281 strlcpy(name, optarg, sizeof(name));
282 dbg("name: %s\n", name);
285 /* remove /sys if given */
286 if (strncmp(optarg, sysfs_path, strlen(sysfs_path)) == 0)
287 strlcpy(path, &optarg[strlen(sysfs_path)], sizeof(path));
289 strlcpy(path, optarg, sizeof(path));
290 dbg("path: %s\n", path);
293 dbg("udev query: %s\n", optarg);
294 action = ACTION_QUERY;
295 if (strcmp(optarg, "name") == 0) {
299 if (strcmp(optarg, "symlink") == 0) {
300 query = QUERY_SYMLINK;
303 if (strcmp(optarg, "path") == 0) {
307 if (strcmp(optarg, "env") == 0) {
311 if (strcmp(optarg, "all") == 0) {
315 fprintf(stderr, "unknown query type\n");
319 if (action == ACTION_NONE)
320 action = ACTION_ROOT;
324 action = ACTION_ATTRIBUTE_WALK;
330 printf("%s\n", UDEV_VERSION);
333 printf("udevinfo, version %s\n", UDEV_VERSION);
336 printf("Usage: udevinfo OPTIONS\n"
337 " --query=<type> query database for the specified value:\n"
338 " name name of device node\n"
339 " symlink pointing to node\n"
340 " path sysfs device path\n"
341 " env the device related imported environment\n"
344 " --path=<devpath> sysfs device path used for query or chain\n"
345 " --name=<name> node or symlink name used for query\n"
347 " --root prepend to query result or print udev_root\n"
348 " --attribute-walk print all SYSFS_attributes along the device chain\n"
349 " --export-db export the content of the udev database\n"
350 " --help print this text\n"
361 /* needs devpath or node/symlink name for query */
362 if (path[0] != '\0') {
363 if (udev_db_get_device(udev, path) != 0) {
364 fprintf(stderr, "no record for '%s' in database\n", path);
368 } else if (name[0] != '\0') {
369 if (lookup_device_by_name(udev, name) != 0) {
370 fprintf(stderr, "node name not found\n");
375 fprintf(stderr, "query needs --path or node --name specified\n");
383 printf("%s/%s\n", udev_root, udev->name);
385 printf("%s\n", udev->name);
388 if (list_empty(&udev->symlink_list))
391 list_for_each_entry(name_loop, &udev->symlink_list, node)
392 printf("%s/%s ", udev_root, name_loop->name);
394 list_for_each_entry(name_loop, &udev->symlink_list, node)
395 printf("%s ", name_loop->name);
399 printf("%s\n", udev->dev->devpath);
402 list_for_each_entry(name_loop, &udev->env_list, node)
403 printf("%s\n", name_loop->name);
409 fprintf(stderr, "unknown query type\n");
413 case ACTION_ATTRIBUTE_WALK:
414 if (path[0] != '\0') {
415 if (print_device_chain(path) != 0) {
416 fprintf(stderr, "device not found\n");
420 } else if (name[0] != '\0') {
421 if (lookup_device_by_name(udev, name) != 0) {
422 fprintf(stderr, "node name not found\n");
426 if (print_device_chain(udev->dev->devpath) != 0) {
427 fprintf(stderr, "device not found\n");
432 fprintf(stderr, "attribute walk needs --path or node --name specified\n");
438 printf("%s\n", udev_root);
441 fprintf(stderr, "missing option\n");
447 udev_device_cleanup(udev);