2 * udevinfo - fetches attributes for a device
4 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation version 2 of the License.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 675 Mass Ave, Cambridge, MA 02139, USA.
30 #include "libsysfs/sysfs/libsysfs.h"
31 #include "libsysfs/dlist.h"
33 #include "udev_utils.h"
34 #include "udev_version.h"
39 #define SYSFS_VALUE_SIZE 256
42 void log_message (int level, const char *format, ...)
46 va_start(args, format);
47 vsyslog(level, format, args);
52 static int print_all_attributes(const char *path)
54 struct dlist *attributes;
55 struct sysfs_attribute *attr;
56 struct sysfs_directory *sysfs_dir;
57 char value[SYSFS_VALUE_SIZE];
61 sysfs_dir = sysfs_open_directory(path);
62 if (sysfs_dir == NULL)
65 attributes = sysfs_get_dir_attributes(sysfs_dir);
66 if (attributes == NULL) {
71 dlist_for_each_data(attributes, attr, struct sysfs_attribute) {
72 if (attr->value != NULL) {
73 strfieldcpy(value, attr->value);
78 /* remove trailing newline */
79 if (value[len-1] == '\n') {
84 /* skip nonprintable values */
86 if (isprint(value[len-1]) == 0)
91 printf(" SYSFS{%s}=\"%s\"\n", attr->name, value);
97 sysfs_close_directory(sysfs_dir);
102 static int print_record(struct udevice *udev)
104 printf("P: %s\n", udev->devpath);
105 printf("N: %s\n", udev->name);
106 printf("S: %s\n", udev->symlink);
119 static int print_device_chain(const char *path)
121 struct sysfs_class_device *class_dev;
122 struct sysfs_class_device *class_dev_parent;
123 struct sysfs_attribute *attr;
124 struct sysfs_device *sysfs_dev;
125 struct sysfs_device *sysfs_dev_parent;
128 /* get the class dev */
129 class_dev = sysfs_open_class_device_path(path);
130 if (class_dev == NULL) {
131 printf("couldn't get the class device\n");
135 printf("\nudevinfo starts with the device the node belongs to and then walks up the\n"
136 "device chain, to print for every device found, all possibly useful attributes\n"
137 "in the udev key format.\n"
138 "Only attributes within one device section may be used together in one rule,\n"
139 "to match the device for which the node will be created.\n"
142 /* look for the 'dev' file */
143 attr = sysfs_get_classdev_attr(class_dev, "dev");
145 printf("device '%s' has major:minor %s", class_dev->path, attr->value);
147 /* open sysfs class device directory and print all attributes */
148 printf(" looking at class device '%s':\n", class_dev->path);
149 if (print_all_attributes(class_dev->path) != 0) {
150 printf("couldn't open class device directory\n");
155 /* get the device link (if parent exists look here) */
156 class_dev_parent = sysfs_get_classdev_parent(class_dev);
157 if (class_dev_parent != NULL)
158 sysfs_dev = sysfs_get_classdev_device(class_dev_parent);
160 sysfs_dev = sysfs_get_classdev_device(class_dev);
162 if (sysfs_dev != NULL)
163 printf("follow the class device's \"device\"\n");
165 /* look the device chain upwards */
166 while (sysfs_dev != NULL) {
167 printf(" looking at the device chain at '%s':\n", sysfs_dev->path);
168 printf(" BUS=\"%s\"\n", sysfs_dev->bus);
169 printf(" ID=\"%s\"\n", sysfs_dev->bus_id);
171 /* open sysfs device directory and print all attributes */
172 print_all_attributes(sysfs_dev->path);
174 sysfs_dev_parent = sysfs_get_device_parent(sysfs_dev);
175 if (sysfs_dev_parent == NULL)
178 sysfs_dev = sysfs_dev_parent;
182 sysfs_close_class_device(class_dev);
186 /* print all class/main block devices with major/minor, physical device, driver and bus */
187 static int print_sysfs_devices(void)
189 struct dlist *subsyslist;
192 subsyslist = sysfs_open_subsystem_list("class");
196 dlist_for_each_data(subsyslist, class, char) {
197 struct sysfs_class *cls;
198 struct dlist *class_devices;
199 struct sysfs_class_device *class_dev;
200 struct sysfs_device *phys_dev;
201 unsigned int major, minor;
203 cls = sysfs_open_class(class);
207 class_devices = sysfs_get_class_devices(cls);
211 dlist_for_each_data(class_devices, class_dev, struct sysfs_class_device) {
212 struct sysfs_attribute *attr;
215 printf("DEVPATH '%s'\n", class_dev->path);
216 printf("SUBSYSTEM '%s'\n", class_dev->classname);
218 attr = sysfs_get_classdev_attr(class_dev, "dev");
220 sscanf(attr->value, "%u:%u", &major, &minor);
221 printf("MAJOR %u\n", major);
222 printf("MINOR %u\n", minor);
225 phys_dev = sysfs_get_classdev_device(class_dev);
227 printf("PHYSDEVPATH '%s'\n", phys_dev->path);
228 if (phys_dev->bus[0] != '\0')
229 printf("PHYSDEVBUS '%s'\n", phys_dev->bus);
231 if (phys_dev->driver_name[0] != '\0')
232 printf("PHYSDEVDRIVER '%s'\n", phys_dev->driver_name);
235 sysfs_close_class(cls);
237 sysfs_close_list(subsyslist);
242 static int process_options(int argc, char *argv[])
244 static const char short_options[] = "an:p:q:rsVh";
250 enum query_type query = NONE;
251 char result[1024] = "";
252 char path[NAME_SIZE] = "";
253 char name[NAME_SIZE] = "";
254 char temp[NAME_SIZE];
257 /* get command line options */
259 option = getopt(argc, argv, short_options);
263 dbg("option '%c'", option);
266 dbg("udev name: %s\n", optarg);
267 strfieldcpy(name, optarg);
271 dbg("udev path: %s\n", optarg);
272 strfieldcpy(path, optarg);
276 dbg("udev query: %s\n", optarg);
278 if (strcmp(optarg, "name") == 0) {
283 if (strcmp(optarg, "symlink") == 0) {
288 if (strcmp(optarg, "path") == 0) {
293 if (strcmp(optarg, "all") == 0) {
298 printf("unknown query type\n");
306 print_sysfs_devices();
314 printf("udevinfo, version %s\n", UDEV_VERSION);
325 /* process options */
327 if (path[0] != '\0') {
328 /* remove sysfs_path if given */
329 if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
330 pos = path + strlen(sysfs_path);
332 if (path[0] != '/') {
333 /* prepend '/' if missing */
334 strfieldcat(temp, "/");
335 strfieldcat(temp, path);
341 memset(&udev, 0x00, sizeof(struct udevice));
342 strfieldcpy(udev.devpath, pos);
343 retval = udev_db_get_device(&udev);
345 printf("device not found in database\n");
351 if (name[0] != '\0') {
352 /* remove udev_root if given */
353 int len = strlen(udev_root);
355 if (strncmp(name, udev_root, len) == 0) {
360 memset(&udev, 0x00, sizeof(struct udevice));
361 strfieldcpy(udev.name, pos);
362 retval = udev_db_get_device_byname(&udev, pos);
364 printf("device not found in database\n");
371 printf("query needs device path(-p) or node name(-n) specified\n");
378 snprintf(result, NAME_SIZE-1, "%s/%s", udev_root, udev.name);
379 result[NAME_SIZE-1] = '\0';
381 strfieldcpy(result, udev.name);
389 char slink[NAME_SIZE];
392 foreach_strpart(udev.symlink, " \n\r", spos, slen) {
393 strncpy(slink, spos, slen);
395 pos += sprintf(pos, "%s/%s ", udev_root, slink);
398 strfieldcpy(result, udev.symlink);
403 strfieldcpy(result, udev.devpath);
413 printf("%s\n", result);
420 if (path[0] == '\0') {
421 printf("attribute walk on device chain needs path(-p) specified\n");
424 if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) {
425 /* prepend sysfs mountpoint if not given */
426 strfieldcpy(temp, path);
427 strfieldcpy(path, sysfs_path);
428 strfieldcat(path, temp);
430 print_device_chain(path);
436 printf("%s\n", udev_root);
441 printf("Usage: udevinfo [-anpqrVh]\n"
442 " -q TYPE query database for the specified value:\n"
443 " 'name' name of device node\n"
444 " 'symlink' pointing to node\n"
445 " 'path' sysfs device path\n"
446 " 'all' all values\n"
448 " -p PATH sysfs device path used for query or chain\n"
449 " -n NAME node/symlink name used for query\n"
451 " -r print udev root\n"
452 " -a print all SYSFS_attributes along the device chain\n"
453 " -s print all sysfs devices with major/minor, physical device and bus\n"
454 " -V print udev version\n"
455 " -h print this help text\n"
460 int main(int argc, char *argv[], char *envp[])
464 logging_init("udevinfo");
466 /* initialize our configuration */
469 rc = process_options(argc, argv);