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);
177 struct name_entry *device;
180 count = udev_db_get_devices_by_name(name, &name_list);
184 info("found %i devices for '%s'", count, name);
186 /* select the device that seems to match */
187 list_for_each_entry(device, &name_list, node) {
188 char filename[PATH_SIZE];
191 udev_device_init(udev);
192 if (udev_db_get_device(udev, device->name) != 0)
194 info("found db entry '%s'", device->name);
196 /* make sure, we don't get a link of a differnt device */
197 strlcpy(filename, udev_root, sizeof(filename));
198 strlcat(filename, "/", sizeof(filename));
199 strlcat(filename, name, sizeof(filename));
200 if (stat(filename, &statbuf) != 0)
202 if (major(udev->devt) > 0 && udev->devt != statbuf.st_rdev) {
203 info("skip '%s', dev_t doesn't match", udev->name);
210 name_list_cleanup(&name_list);
214 int main(int argc, char *argv[], char *envp[])
217 struct udevice *udev;
220 static const struct option options[] = {
221 { "name", 1, NULL, 'n' },
222 { "path", 1, NULL, 'p' },
223 { "query", 1, NULL, 'q' },
224 { "attribute-walk", 0, NULL, 'a' },
225 { "export-db", 0, NULL, 'e' },
226 { "root", 0, NULL, 'r' },
227 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
228 { "help", 0, NULL, 'h' },
235 ACTION_ATTRIBUTE_WALK,
237 } action = ACTION_NONE;
246 } query = QUERY_NONE;
248 char path[PATH_SIZE] = "";
249 char name[PATH_SIZE] = "";
250 struct name_entry *name_loop;
253 logging_init("udevinfo");
257 udev = udev_device_init(NULL);
263 /* get command line options */
265 option = getopt_long(argc, argv, "aen:p:q:rVh", options, NULL);
269 dbg("option '%c'", option);
272 /* remove /dev if given */
273 if (strncmp(optarg, udev_root, strlen(udev_root)) == 0)
274 strlcpy(name, &optarg[strlen(udev_root)+1], sizeof(name));
276 strlcpy(name, optarg, sizeof(name));
277 dbg("name: %s\n", name);
280 /* remove /sys if given */
281 if (strncmp(optarg, sysfs_path, strlen(sysfs_path)) == 0)
282 strlcpy(path, &optarg[strlen(sysfs_path)], sizeof(path));
284 strlcpy(path, optarg, sizeof(path));
285 dbg("path: %s\n", path);
288 dbg("udev query: %s\n", optarg);
289 action = ACTION_QUERY;
290 if (strcmp(optarg, "name") == 0) {
294 if (strcmp(optarg, "symlink") == 0) {
295 query = QUERY_SYMLINK;
298 if (strcmp(optarg, "path") == 0) {
302 if (strcmp(optarg, "env") == 0) {
306 if (strcmp(optarg, "all") == 0) {
310 fprintf(stderr, "unknown query type\n");
314 if (action == ACTION_NONE)
315 action = ACTION_ROOT;
319 action = ACTION_ATTRIBUTE_WALK;
325 printf("%s\n", UDEV_VERSION);
328 printf("udevinfo, version %s\n", UDEV_VERSION);
331 printf("Usage: udevinfo OPTIONS\n"
332 " --query=<type> query database for the specified value:\n"
333 " name name of device node\n"
334 " symlink pointing to node\n"
335 " path sysfs device path\n"
336 " env the device related imported environment\n"
339 " --path=<devpath> sysfs device path used for query or chain\n"
340 " --name=<name> node or symlink name used for query\n"
342 " --root prepend to query result or print udev_root\n"
343 " --attribute-walk print all SYSFS_attributes along the device chain\n"
344 " --export-db export the content of the udev database\n"
345 " --help print this text\n"
356 /* needs devpath or node/symlink name for query */
357 if (path[0] != '\0') {
358 if (udev_db_get_device(udev, path) != 0) {
359 fprintf(stderr, "no record for '%s' in database\n", path);
363 } else if (name[0] != '\0') {
364 if (lookup_device_by_name(udev, name) != 0) {
365 fprintf(stderr, "node name not found\n");
370 fprintf(stderr, "query needs --path or node --name specified\n");
378 printf("%s/%s\n", udev_root, udev->name);
380 printf("%s\n", udev->name);
383 if (list_empty(&udev->symlink_list))
386 list_for_each_entry(name_loop, &udev->symlink_list, node)
387 printf("%s/%s ", udev_root, name_loop->name);
389 list_for_each_entry(name_loop, &udev->symlink_list, node)
390 printf("%s ", name_loop->name);
394 printf("%s\n", udev->dev->devpath);
397 list_for_each_entry(name_loop, &udev->env_list, node)
398 printf("%s\n", name_loop->name);
404 fprintf(stderr, "unknown query type\n");
408 case ACTION_ATTRIBUTE_WALK:
409 if (path[0] != '\0') {
410 if (print_device_chain(path) != 0) {
411 fprintf(stderr, "device not found\n");
415 } else if (name[0] != '\0') {
416 if (lookup_device_by_name(udev, name) != 0) {
417 fprintf(stderr, "node name not found\n");
421 if (print_device_chain(udev->dev->devpath) != 0) {
422 fprintf(stderr, "device not found\n");
427 fprintf(stderr, "attribute walk needs --path or node --name specified\n");
433 printf("%s\n", udev_root);
436 fprintf(stderr, "missing option\n");
442 udev_device_cleanup(udev);