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 list_for_each_entry(name_loop, &udev->symlink_list, node)
148 printf("S: %s\n", name_loop->name);
149 list_for_each_entry(name_loop, &udev->env_list, node)
150 printf("E: %s\n", name_loop->name);
153 static void export_name_devpath(struct udevice *udev) {
154 printf("%s=%s/%s\n", udev->dev->devpath, udev_root, udev->name);
157 static void export_record(struct udevice *udev) {
162 static void export_db(void fnct(struct udevice *udev)) {
163 LIST_HEAD(name_list);
164 struct name_entry *name_loop;
166 udev_db_get_all_entries(&name_list);
167 list_for_each_entry(name_loop, &name_list, node) {
168 struct udevice *udev_db;
170 udev_db = udev_device_init();
173 if (udev_db_get_device(udev_db, name_loop->name) == 0)
175 udev_device_cleanup(udev_db);
177 name_list_cleanup(&name_list);
180 int main(int argc, char *argv[], char *envp[])
183 struct udevice *udev;
186 static const struct option options[] = {
187 { "name", 1, NULL, 'n' },
188 { "path", 1, NULL, 'p' },
189 { "query", 1, NULL, 'q' },
190 { "attribute-walk", 0, NULL, 'a' },
191 { "export-db", 0, NULL, 'e' },
192 { "root", 0, NULL, 'r' },
193 { "version", 0, NULL, 'V' },
194 { "help", 0, NULL, 'h' },
201 ACTION_ATTRIBUTE_WALK,
203 } action = ACTION_NONE;
212 } query = QUERY_NONE;
214 char path[PATH_SIZE] = "";
215 char name[PATH_SIZE] = "";
216 struct name_entry *name_loop;
219 logging_init("udevinfo");
223 udev = udev_device_init();
229 /* get command line options */
231 option = getopt_long(argc, argv, "aden:p:q:rVh", options, NULL);
235 dbg("option '%c'", option);
238 /* remove /dev if given */
239 if (strncmp(optarg, udev_root, strlen(udev_root)) == 0)
240 strlcpy(name, &optarg[strlen(udev_root)+1], sizeof(name));
242 strlcpy(name, optarg, sizeof(name));
243 dbg("name: %s\n", name);
246 /* remove /sys if given */
247 if (strncmp(optarg, sysfs_path, strlen(sysfs_path)) == 0)
248 strlcpy(path, &optarg[strlen(sysfs_path)], sizeof(path));
250 strlcpy(path, optarg, sizeof(path));
251 dbg("path: %s\n", path);
254 dbg("udev query: %s\n", optarg);
255 action = ACTION_QUERY;
256 if (strcmp(optarg, "name") == 0) {
260 if (strcmp(optarg, "symlink") == 0) {
261 query = QUERY_SYMLINK;
264 if (strcmp(optarg, "path") == 0) {
268 if (strcmp(optarg, "env") == 0) {
272 if (strcmp(optarg, "all") == 0) {
276 fprintf(stderr, "unknown query type\n");
280 if (action == ACTION_NONE)
281 action = ACTION_ROOT;
285 action = ACTION_ATTRIBUTE_WALK;
288 export_db(export_name_devpath);
291 export_db(export_record);
294 printf("udevinfo, version %s\n", UDEV_VERSION);
297 printf("Usage: udevinfo OPTIONS\n"
298 " --query=<type> query database for the specified value:\n"
299 " name name of device node\n"
300 " symlink pointing to node\n"
301 " path sysfs device path\n"
302 " env the device related imported environment\n"
305 " --path=<devpath> sysfs device path used for query or chain\n"
306 " --name=<name> node or symlink name used for query\n"
308 " --root prepend to query result or print udev_root\n"
309 " --attribute-walk print all SYSFS_attributes along the device chain\n"
310 " --export-db export the content of the udev database\n"
311 " --version print udev version\n"
312 " --help print this text\n"
323 /* needs devpath or node/symlink name for query */
324 if (path[0] != '\0') {
325 if (udev_db_get_device(udev, path) != 0) {
326 fprintf(stderr, "no record for '%s' in database\n", path);
330 } else if (name[0] != '\0') {
331 char devpath[PATH_SIZE];
333 if (udev_db_lookup_name(name, devpath, sizeof(devpath)) != 0) {
334 fprintf(stderr, "node name not found\n");
338 udev_db_get_device(udev, devpath);
340 fprintf(stderr, "query needs --path or node --name specified\n");
348 printf("%s/%s\n", udev_root, udev->name);
350 printf("%s\n", udev->name);
353 if (list_empty(&udev->symlink_list))
356 list_for_each_entry(name_loop, &udev->symlink_list, node)
357 printf("%s/%s ", udev_root, name_loop->name);
359 list_for_each_entry(name_loop, &udev->symlink_list, node)
360 printf("%s ", name_loop->name);
364 printf("%s\n", udev->dev->devpath);
367 list_for_each_entry(name_loop, &udev->env_list, node)
368 printf("%s\n", name_loop->name);
374 fprintf(stderr, "unknown query type\n");
378 case ACTION_ATTRIBUTE_WALK:
379 if (path[0] != '\0') {
380 if (print_device_chain(path) != 0) {
381 fprintf(stderr, "device not found\n");
385 } else if (name[0] != '\0') {
386 char devpath[PATH_SIZE];
388 if (udev_db_lookup_name(name, devpath, sizeof(devpath)) != 0) {
389 fprintf(stderr, "node name not found\n");
393 if (print_device_chain(devpath) != 0) {
394 fprintf(stderr, "device not found\n");
399 fprintf(stderr, "attribute walk needs --path or node --name specified\n");
405 printf("%s\n", udev_root);
408 fprintf(stderr, "missing option\n");
414 udev_device_cleanup(udev);