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 if (strcmp(dent->d_name, "uevent") == 0)
73 strlcpy(filename, path, sizeof(filename));
74 strlcat(filename, "/", sizeof(filename));
75 strlcat(filename, dent->d_name, sizeof(filename));
76 if (lstat(filename, &statbuf) != 0)
78 if (S_ISLNK(statbuf.st_mode))
81 attr_value = sysfs_attr_get_value(devpath, dent->d_name);
82 if (attr_value == NULL)
84 len = strlcpy(value, attr_value, sizeof(value));
85 if(len >= sizeof(value))
86 len = sizeof(value) - 1;
87 dbg("attr '%s'='%s'(%zi)", dent->d_name, value, len);
89 /* remove trailing newlines */
90 while (len && value[len-1] == '\n')
93 /* skip nonprintable attributes */
94 while (len && isprint(value[len-1]))
97 dbg("attribute value of '%s' non-printable, skip", dent->d_name);
101 replace_chars(value, ALLOWED_CHARS_INPUT);
102 printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
108 static int print_device_chain(const char *devpath)
110 struct sysfs_device *dev;
112 dev = sysfs_device_get(devpath);
117 "Udevinfo starts with the device specified by the devpath and then\n"
118 "walks up the chain of parent devices. It prints for every device\n"
119 "found, all possible attributes in the udev rules key format.\n"
120 "A rule to match, can be composed by the attributes of the device\n"
121 "and the attributes from one single parent device.\n"
124 printf(" looking at device '%s':\n", dev->devpath);
125 printf(" KERNEL==\"%s\"\n", dev->kernel);
126 printf(" SUBSYSTEM==\"%s\"\n", dev->subsystem);
127 printf(" DRIVER==\"%s\"\n", dev->driver);
128 print_all_attributes(dev->devpath, "ATTR");
130 /* walk up the chain of devices */
132 dev = sysfs_device_get_parent(dev);
135 printf(" looking at parent device '%s':\n", dev->devpath);
136 printf(" KERNELS==\"%s\"\n", dev->kernel);
137 printf(" SUBSYSTEMS==\"%s\"\n", dev->subsystem);
138 printf(" DRIVERS==\"%s\"\n", dev->driver);
140 print_all_attributes(dev->devpath, "ATTRS");
146 static void print_record(struct udevice *udev)
148 struct name_entry *name_loop;
150 printf("P: %s\n", udev->dev->devpath);
151 printf("N: %s\n", udev->name);
152 list_for_each_entry(name_loop, &udev->symlink_list, node)
153 printf("S: %s\n", name_loop->name);
154 if (udev->link_priority != 0)
155 printf("L: %i\n", udev->link_priority);
156 if (udev->partitions != 0)
157 printf("A:%u\n", udev->partitions);
158 if (udev->ignore_remove)
159 printf("R:%u\n", udev->ignore_remove);
160 list_for_each_entry(name_loop, &udev->env_list, node)
161 printf("E: %s\n", name_loop->name);
164 static void export_db(void) {
165 LIST_HEAD(name_list);
166 struct name_entry *name_loop;
168 udev_db_get_all_entries(&name_list);
169 list_for_each_entry(name_loop, &name_list, node) {
170 struct udevice *udev_db;
172 udev_db = udev_device_init(NULL);
175 if (udev_db_get_device(udev_db, name_loop->name) == 0)
176 print_record(udev_db);
178 udev_device_cleanup(udev_db);
180 name_list_cleanup(&name_list);
183 static int lookup_device_by_name(struct udevice *udev, const char *name)
185 LIST_HEAD(name_list);
187 struct name_entry *device;
190 count = udev_db_get_devices_by_name(name, &name_list);
194 info("found %i devices for '%s'", count, name);
196 /* select the device that seems to match */
197 list_for_each_entry(device, &name_list, node) {
198 char filename[PATH_SIZE];
201 udev_device_init(udev);
202 if (udev_db_get_device(udev, device->name) != 0)
204 info("found db entry '%s'", device->name);
206 /* make sure, we don't get a link of a differnt device */
207 strlcpy(filename, udev_root, sizeof(filename));
208 strlcat(filename, "/", sizeof(filename));
209 strlcat(filename, name, sizeof(filename));
210 if (stat(filename, &statbuf) != 0)
212 if (major(udev->devt) > 0 && udev->devt != statbuf.st_rdev) {
213 info("skip '%s', dev_t doesn't match", udev->name);
220 name_list_cleanup(&name_list);
224 int main(int argc, char *argv[], char *envp[])
227 struct udevice *udev;
230 static const struct option options[] = {
231 { "name", 1, NULL, 'n' },
232 { "path", 1, NULL, 'p' },
233 { "query", 1, NULL, 'q' },
234 { "attribute-walk", 0, NULL, 'a' },
235 { "export-db", 0, NULL, 'e' },
236 { "root", 0, NULL, 'r' },
237 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
238 { "help", 0, NULL, 'h' },
245 ACTION_ATTRIBUTE_WALK,
247 } action = ACTION_NONE;
256 } query = QUERY_NONE;
258 char path[PATH_SIZE] = "";
259 char name[PATH_SIZE] = "";
260 struct name_entry *name_loop;
263 logging_init("udevinfo");
267 udev = udev_device_init(NULL);
274 option = getopt_long(argc, argv, "aen:p:q:rVh", options, NULL);
278 dbg("option '%c'", option);
281 /* remove /dev if given */
282 if (strncmp(optarg, udev_root, strlen(udev_root)) == 0)
283 strlcpy(name, &optarg[strlen(udev_root)+1], sizeof(name));
285 strlcpy(name, optarg, sizeof(name));
286 dbg("name: %s", name);
289 /* remove /sys if given */
290 if (strncmp(optarg, sysfs_path, strlen(sysfs_path)) == 0)
291 strlcpy(path, &optarg[strlen(sysfs_path)], sizeof(path));
293 strlcpy(path, optarg, sizeof(path));
294 dbg("path: %s", path);
297 action = ACTION_QUERY;
298 if (strcmp(optarg, "name") == 0) {
302 if (strcmp(optarg, "symlink") == 0) {
303 query = QUERY_SYMLINK;
306 if (strcmp(optarg, "path") == 0) {
310 if (strcmp(optarg, "env") == 0) {
314 if (strcmp(optarg, "all") == 0) {
318 fprintf(stderr, "unknown query type\n");
322 if (action == ACTION_NONE)
323 action = ACTION_ROOT;
327 action = ACTION_ATTRIBUTE_WALK;
333 printf("%s\n", UDEV_VERSION);
336 printf("udevinfo, version %s\n", UDEV_VERSION);
339 printf("Usage: udevinfo OPTIONS\n"
340 " --query=<type> query database for the specified value:\n"
341 " name name of device node\n"
342 " symlink pointing to node\n"
343 " path sysfs device path\n"
344 " env the device related imported environment\n"
347 " --path=<devpath> sysfs device path used for query or chain\n"
348 " --name=<name> node or symlink name used for query\n"
350 " --root prepend to query result or print udev_root\n"
351 " --attribute-walk print all SYSFS_attributes along the device chain\n"
352 " --export-db export the content of the udev database\n"
353 " --help print this text\n"
364 /* needs devpath or node/symlink name for query */
365 if (path[0] != '\0') {
366 if (udev_db_get_device(udev, path) != 0) {
367 fprintf(stderr, "no record for '%s' in database\n", path);
371 } else if (name[0] != '\0') {
372 if (lookup_device_by_name(udev, name) != 0) {
373 fprintf(stderr, "node name not found\n");
378 fprintf(stderr, "query needs --path or node --name specified\n");
386 printf("%s/%s\n", udev_root, udev->name);
388 printf("%s\n", udev->name);
391 list_for_each_entry(name_loop, &udev->symlink_list, node) {
392 char c = name_loop->node.next != &udev->symlink_list ? ' ' : '\n';
395 printf("%s/%s%c", udev_root, name_loop->name, c);
397 printf("%s%c", name_loop->name, c);
401 printf("%s\n", udev->dev->devpath);
404 list_for_each_entry(name_loop, &udev->env_list, node)
405 printf("%s\n", name_loop->name);
411 fprintf(stderr, "unknown query type\n");
415 case ACTION_ATTRIBUTE_WALK:
416 if (path[0] != '\0') {
417 if (print_device_chain(path) != 0) {
418 fprintf(stderr, "no valid sysfs device found\n");
422 } else if (name[0] != '\0') {
423 if (lookup_device_by_name(udev, name) != 0) {
424 fprintf(stderr, "node name not found\n");
428 if (print_device_chain(udev->dev->devpath) != 0) {
429 fprintf(stderr, "no valid sysfs device found\n");
434 fprintf(stderr, "attribute walk needs --path or node --name specified\n");
440 printf("%s\n", udev_root);
443 fprintf(stderr, "missing option\n");
449 udev_device_cleanup(udev);