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 if(len >= sizeof(value))
83 len = sizeof(value) - 1;
84 dbg("attr '%s'='%s'(%zi)", dent->d_name, value, len);
86 /* remove trailing newlines */
87 while (len && value[len-1] == '\n')
90 /* skip nonprintable attributes */
91 while (len && isprint(value[len-1]))
94 dbg("attribute value of '%s' non-printable, skip", dent->d_name);
98 replace_chars(value, ALLOWED_CHARS_INPUT);
99 printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
105 static int print_device_chain(const char *devpath)
107 struct sysfs_device *dev;
109 dev = sysfs_device_get(devpath);
114 "Udevinfo starts with the device specified by the devpath and then\n"
115 "walks up the chain of parent devices. It prints for every device\n"
116 "found, all possible attributes in the udev rules key format.\n"
117 "A rule to match, can be composed by the attributes of the device\n"
118 "and the attributes from one single parent device.\n"
121 printf(" looking at device '%s':\n", dev->devpath);
122 printf(" KERNEL==\"%s\"\n", dev->kernel);
123 printf(" SUBSYSTEM==\"%s\"\n", dev->subsystem);
124 printf(" DRIVER==\"%s\"\n", dev->driver);
125 print_all_attributes(dev->devpath, "ATTR");
127 /* walk up the chain of devices */
129 dev = sysfs_device_get_parent(dev);
132 printf(" looking at parent device '%s':\n", dev->devpath);
133 printf(" KERNELS==\"%s\"\n", dev->kernel);
134 printf(" SUBSYSTEMS==\"%s\"\n", dev->subsystem);
135 printf(" DRIVERS==\"%s\"\n", dev->driver);
137 print_all_attributes(dev->devpath, "ATTRS");
143 static void print_record(struct udevice *udev)
145 struct name_entry *name_loop;
147 printf("P: %s\n", udev->dev->devpath);
148 printf("N: %s\n", udev->name);
149 list_for_each_entry(name_loop, &udev->symlink_list, node)
150 printf("S: %s\n", name_loop->name);
151 if (udev->link_priority != 0)
152 printf("L: %i\n", udev->link_priority);
153 if (udev->partitions != 0)
154 printf("A:%u\n", udev->partitions);
155 if (udev->ignore_remove)
156 printf("R:%u\n", udev->ignore_remove);
157 list_for_each_entry(name_loop, &udev->env_list, node)
158 printf("E: %s\n", name_loop->name);
161 static void export_db(void) {
162 LIST_HEAD(name_list);
163 struct name_entry *name_loop;
165 udev_db_get_all_entries(&name_list);
166 list_for_each_entry(name_loop, &name_list, node) {
167 struct udevice *udev_db;
169 udev_db = udev_device_init(NULL);
172 if (udev_db_get_device(udev_db, name_loop->name) == 0)
173 print_record(udev_db);
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);
184 struct name_entry *device;
187 count = udev_db_get_devices_by_name(name, &name_list);
191 info("found %i devices for '%s'", count, name);
193 /* select the device that seems to match */
194 list_for_each_entry(device, &name_list, node) {
195 char filename[PATH_SIZE];
198 udev_device_init(udev);
199 if (udev_db_get_device(udev, device->name) != 0)
201 info("found db entry '%s'", device->name);
203 /* make sure, we don't get a link of a differnt device */
204 strlcpy(filename, udev_root, sizeof(filename));
205 strlcat(filename, "/", sizeof(filename));
206 strlcat(filename, name, sizeof(filename));
207 if (stat(filename, &statbuf) != 0)
209 if (major(udev->devt) > 0 && udev->devt != statbuf.st_rdev) {
210 info("skip '%s', dev_t doesn't match", udev->name);
217 name_list_cleanup(&name_list);
221 int main(int argc, char *argv[], char *envp[])
224 struct udevice *udev;
227 static const struct option options[] = {
228 { "name", 1, NULL, 'n' },
229 { "path", 1, NULL, 'p' },
230 { "query", 1, NULL, 'q' },
231 { "attribute-walk", 0, NULL, 'a' },
232 { "export-db", 0, NULL, 'e' },
233 { "root", 0, NULL, 'r' },
234 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
235 { "help", 0, NULL, 'h' },
242 ACTION_ATTRIBUTE_WALK,
244 } action = ACTION_NONE;
253 } query = QUERY_NONE;
255 char path[PATH_SIZE] = "";
256 char name[PATH_SIZE] = "";
257 struct name_entry *name_loop;
260 logging_init("udevinfo");
264 udev = udev_device_init(NULL);
271 option = getopt_long(argc, argv, "aen:p:q:rVh", options, NULL);
275 dbg("option '%c'", option);
278 /* remove /dev if given */
279 if (strncmp(optarg, udev_root, strlen(udev_root)) == 0)
280 strlcpy(name, &optarg[strlen(udev_root)+1], sizeof(name));
282 strlcpy(name, optarg, sizeof(name));
283 dbg("name: %s", name);
286 /* remove /sys if given */
287 if (strncmp(optarg, sysfs_path, strlen(sysfs_path)) == 0)
288 strlcpy(path, &optarg[strlen(sysfs_path)], sizeof(path));
290 strlcpy(path, optarg, sizeof(path));
291 dbg("path: %s", path);
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 list_for_each_entry(name_loop, &udev->symlink_list, node) {
389 char c = name_loop->node.next != &udev->symlink_list ? ' ' : '\n';
392 printf("%s/%s%c", udev_root, name_loop->name, c);
394 printf("%s%c", name_loop->name, c);
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, "no valid sysfs device 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, "no valid sysfs device 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);