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_db(void) {
154 LIST_HEAD(name_list);
155 struct name_entry *name_loop;
157 udev_db_get_all_entries(&name_list);
158 list_for_each_entry(name_loop, &name_list, node) {
159 struct udevice *udev_db;
161 udev_db = udev_device_init(NULL);
164 if (udev_db_get_device(udev_db, name_loop->name) == 0)
165 print_record(udev_db);
167 udev_device_cleanup(udev_db);
169 name_list_cleanup(&name_list);
172 static int lookup_device_by_name(struct udevice *udev, const char *name)
174 LIST_HEAD(name_list);
175 struct name_entry *device;
178 if (udev_db_get_devices_by_name(name, &name_list) <= 0)
181 /* select the device that matches the dev_t of name */
182 list_for_each_entry(device, &name_list, node) {
183 char filename[PATH_SIZE];
186 udev_device_init(udev);
187 if (udev_db_get_device(udev, device->name) != 0)
189 info("found db entry '%s'", device->name);
191 strlcpy(filename, udev_root, sizeof(filename));
192 strlcat(filename, "/", sizeof(filename));
193 strlcat(filename, name, sizeof(filename));
194 if (stat(filename, &statbuf) != 0)
196 if (statbuf.st_rdev == udev->devt) {
197 info("found '%s', dev_t matches", udev->name);
203 name_list_cleanup(&name_list);
207 int main(int argc, char *argv[], char *envp[])
210 struct udevice *udev;
213 static const struct option options[] = {
214 { "name", 1, NULL, 'n' },
215 { "path", 1, NULL, 'p' },
216 { "query", 1, NULL, 'q' },
217 { "attribute-walk", 0, NULL, 'a' },
218 { "export-db", 0, NULL, 'e' },
219 { "root", 0, NULL, 'r' },
220 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
221 { "help", 0, NULL, 'h' },
228 ACTION_ATTRIBUTE_WALK,
230 } action = ACTION_NONE;
239 } query = QUERY_NONE;
241 char path[PATH_SIZE] = "";
242 char name[PATH_SIZE] = "";
243 struct name_entry *name_loop;
246 logging_init("udevinfo");
250 udev = udev_device_init(NULL);
256 /* get command line options */
258 option = getopt_long(argc, argv, "aen:p:q:rVh", options, NULL);
262 dbg("option '%c'", option);
265 /* remove /dev if given */
266 if (strncmp(optarg, udev_root, strlen(udev_root)) == 0)
267 strlcpy(name, &optarg[strlen(udev_root)+1], sizeof(name));
269 strlcpy(name, optarg, sizeof(name));
270 dbg("name: %s\n", name);
273 /* remove /sys if given */
274 if (strncmp(optarg, sysfs_path, strlen(sysfs_path)) == 0)
275 strlcpy(path, &optarg[strlen(sysfs_path)], sizeof(path));
277 strlcpy(path, optarg, sizeof(path));
278 dbg("path: %s\n", path);
281 dbg("udev query: %s\n", optarg);
282 action = ACTION_QUERY;
283 if (strcmp(optarg, "name") == 0) {
287 if (strcmp(optarg, "symlink") == 0) {
288 query = QUERY_SYMLINK;
291 if (strcmp(optarg, "path") == 0) {
295 if (strcmp(optarg, "env") == 0) {
299 if (strcmp(optarg, "all") == 0) {
303 fprintf(stderr, "unknown query type\n");
307 if (action == ACTION_NONE)
308 action = ACTION_ROOT;
312 action = ACTION_ATTRIBUTE_WALK;
318 printf("%s\n", UDEV_VERSION);
321 printf("udevinfo, version %s\n", UDEV_VERSION);
324 printf("Usage: udevinfo OPTIONS\n"
325 " --query=<type> query database for the specified value:\n"
326 " name name of device node\n"
327 " symlink pointing to node\n"
328 " path sysfs device path\n"
329 " env the device related imported environment\n"
332 " --path=<devpath> sysfs device path used for query or chain\n"
333 " --name=<name> node or symlink name used for query\n"
335 " --root prepend to query result or print udev_root\n"
336 " --attribute-walk print all SYSFS_attributes along the device chain\n"
337 " --export-db export the content of the udev database\n"
338 " --help print this text\n"
349 /* needs devpath or node/symlink name for query */
350 if (path[0] != '\0') {
351 if (udev_db_get_device(udev, path) != 0) {
352 fprintf(stderr, "no record for '%s' in database\n", path);
356 } else if (name[0] != '\0') {
357 if (lookup_device_by_name(udev, name) != 0) {
358 fprintf(stderr, "node name not found\n");
363 fprintf(stderr, "query needs --path or node --name specified\n");
371 printf("%s/%s\n", udev_root, udev->name);
373 printf("%s\n", udev->name);
376 if (list_empty(&udev->symlink_list))
379 list_for_each_entry(name_loop, &udev->symlink_list, node)
380 printf("%s/%s ", udev_root, name_loop->name);
382 list_for_each_entry(name_loop, &udev->symlink_list, node)
383 printf("%s ", name_loop->name);
387 printf("%s\n", udev->dev->devpath);
390 list_for_each_entry(name_loop, &udev->env_list, node)
391 printf("%s\n", name_loop->name);
397 fprintf(stderr, "unknown query type\n");
401 case ACTION_ATTRIBUTE_WALK:
402 if (path[0] != '\0') {
403 if (print_device_chain(path) != 0) {
404 fprintf(stderr, "device not found\n");
408 } else if (name[0] != '\0') {
409 if (lookup_device_by_name(udev, name) != 0) {
410 fprintf(stderr, "node name not found\n");
414 if (print_device_chain(udev->dev->devpath) != 0) {
415 fprintf(stderr, "device not found\n");
420 fprintf(stderr, "attribute walk needs --path or node --name specified\n");
426 printf("%s\n", udev_root);
429 fprintf(stderr, "missing option\n");
435 udev_device_cleanup(udev);