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 unsigned char logname[LOGNAME_SIZE];
43 void log_message (int level, const char *format, ...)
47 va_start(args, format);
48 vsyslog(level, format, args);
53 static int print_all_attributes(const char *path)
55 struct dlist *attributes;
56 struct sysfs_attribute *attr;
57 struct sysfs_directory *sysfs_dir;
58 char value[SYSFS_VALUE_SIZE];
62 sysfs_dir = sysfs_open_directory(path);
63 if (sysfs_dir == NULL)
66 attributes = sysfs_get_dir_attributes(sysfs_dir);
67 if (attributes == NULL) {
72 dlist_for_each_data(attributes, attr, struct sysfs_attribute) {
73 if (attr->value != NULL) {
74 strfieldcpy(value, attr->value);
79 /* remove trailing newline */
80 if (value[len-1] == '\n') {
85 /* skip nonprintable values */
87 if (isprint(value[len-1]) == 0)
92 printf(" SYSFS{%s}=\"%s\"\n", attr->name, value);
98 sysfs_close_directory(sysfs_dir);
103 static int print_record(struct udevice *udev)
105 printf("P: %s\n", udev->devpath);
106 printf("N: %s\n", udev->name);
107 printf("S: %s\n", udev->symlink);
120 static int print_device_chain(const char *path)
122 struct sysfs_class_device *class_dev;
123 struct sysfs_class_device *class_dev_parent;
124 struct sysfs_attribute *attr;
125 struct sysfs_device *sysfs_dev;
126 struct sysfs_device *sysfs_dev_parent;
129 /* get the class dev */
130 class_dev = sysfs_open_class_device_path(path);
131 if (class_dev == NULL) {
132 printf("couldn't get the class device\n");
136 printf("\nudevinfo starts with the device the node belongs to and then walks up the\n"
137 "device chain, to print for every device found, all possibly useful attributes\n"
138 "in the udev key format.\n"
139 "Only attributes within one device section may be used together in one rule,\n"
140 "to match the device for which the node will be created.\n"
143 /* look for the 'dev' file */
144 attr = sysfs_get_classdev_attr(class_dev, "dev");
146 printf("device '%s' has major:minor %s", class_dev->path, attr->value);
148 /* open sysfs class device directory and print all attributes */
149 printf(" looking at class device '%s':\n", class_dev->path);
150 if (print_all_attributes(class_dev->path) != 0) {
151 printf("couldn't open class device directory\n");
156 /* get the device link (if parent exists look here) */
157 class_dev_parent = sysfs_get_classdev_parent(class_dev);
158 if (class_dev_parent != NULL)
159 sysfs_dev = sysfs_get_classdev_device(class_dev_parent);
161 sysfs_dev = sysfs_get_classdev_device(class_dev);
163 if (sysfs_dev != NULL)
164 printf("follow the class device's \"device\"\n");
166 /* look the device chain upwards */
167 while (sysfs_dev != NULL) {
168 printf(" looking at the device chain at '%s':\n", sysfs_dev->path);
169 printf(" BUS=\"%s\"\n", sysfs_dev->bus);
170 printf(" ID=\"%s\"\n", sysfs_dev->bus_id);
172 /* open sysfs device directory and print all attributes */
173 print_all_attributes(sysfs_dev->path);
175 sysfs_dev_parent = sysfs_get_device_parent(sysfs_dev);
176 if (sysfs_dev_parent == NULL)
179 sysfs_dev = sysfs_dev_parent;
183 sysfs_close_class_device(class_dev);
187 /* print all class/main block devices with major/minor, physical device, driver and bus */
188 static int print_sysfs_devices(void)
190 struct dlist *subsyslist;
193 subsyslist = sysfs_open_subsystem_list("class");
197 dlist_for_each_data(subsyslist, class, char) {
198 struct sysfs_class *cls;
199 struct dlist *class_devices;
200 struct sysfs_class_device *class_dev;
201 struct sysfs_device *phys_dev;
202 unsigned int major, minor;
204 cls = sysfs_open_class(class);
208 class_devices = sysfs_get_class_devices(cls);
212 dlist_for_each_data(class_devices, class_dev, struct sysfs_class_device) {
213 struct sysfs_attribute *attr;
216 printf("DEVPATH '%s'\n", class_dev->path);
217 printf("SUBSYSTEM '%s'\n", class_dev->classname);
219 attr = sysfs_get_classdev_attr(class_dev, "dev");
221 sscanf(attr->value, "%u:%u", &major, &minor);
222 printf("MAJOR %u\n", minor);
223 printf("MINOR %u\n", major);
226 phys_dev = sysfs_get_classdev_device(class_dev);
228 printf("PHYSDEVPATH '%s'\n", phys_dev->path);
229 if (phys_dev->bus[0] != '\0')
230 printf("PHYSDEVBUS '%s'\n", phys_dev->bus);
232 if (phys_dev->driver_name[0] != '\0')
233 printf("PHYSDEVDRIVER '%s'\n", phys_dev->driver_name);
236 sysfs_close_class(cls);
238 sysfs_close_list(subsyslist);
243 static int process_options(int argc, char *argv[])
245 static const char short_options[] = "adn:p:q:rsVh";
251 enum query_type query = NONE;
252 char result[1024] = "";
253 char path[NAME_SIZE] = "";
254 char name[NAME_SIZE] = "";
255 char temp[NAME_SIZE];
258 /* get command line options */
260 option = getopt(argc, argv, short_options);
264 dbg("option '%c'", option);
267 dbg("udev name: %s\n", optarg);
268 strfieldcpy(name, optarg);
272 dbg("udev path: %s\n", optarg);
273 strfieldcpy(path, optarg);
277 dbg("udev query: %s\n", optarg);
279 if (strcmp(optarg, "name") == 0) {
284 if (strcmp(optarg, "symlink") == 0) {
289 if (strcmp(optarg, "path") == 0) {
294 if (strcmp(optarg, "all") == 0) {
299 printf("unknown query type\n");
307 print_sysfs_devices();
315 printf("udevinfo, version %s\n", UDEV_VERSION);
326 /* process options */
328 if (path[0] != '\0') {
329 /* remove sysfs_path if given */
330 if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
331 pos = path + strlen(sysfs_path);
333 if (path[0] != '/') {
334 /* prepend '/' if missing */
335 strfieldcat(temp, "/");
336 strfieldcat(temp, path);
342 memset(&udev, 0x00, sizeof(struct udevice));
343 strfieldcpy(udev.devpath, pos);
344 retval = udev_db_get_device(&udev);
346 printf("device not found in database\n");
352 if (name[0] != '\0') {
353 /* remove udev_root if given */
354 int len = strlen(udev_root);
356 if (strncmp(name, udev_root, len) == 0) {
361 memset(&udev, 0x00, sizeof(struct udevice));
362 strfieldcpy(udev.name, pos);
363 retval = udev_db_get_device_byname(&udev, pos);
365 printf("device not found in database\n");
372 printf("query needs device path(-p) or node name(-n) specified\n");
379 snprintf(result, NAME_SIZE-1, "%s/%s", udev_root, udev.name);
380 result[NAME_SIZE-1] = '\0';
382 strfieldcpy(result, udev.name);
390 char slink[NAME_SIZE];
393 foreach_strpart(udev.symlink, " \n\r", spos, slen) {
394 strncpy(slink, spos, slen);
396 pos += sprintf(pos, "%s/%s ", udev_root, slink);
399 strfieldcpy(result, udev.symlink);
404 strfieldcpy(result, path);
414 printf("%s\n", result);
421 if (path[0] == '\0') {
422 printf("attribute walk on device chain needs path(-p) specified\n");
425 if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) {
426 /* prepend sysfs mountpoint if not given */
427 strfieldcpy(temp, path);
428 strfieldcpy(path, sysfs_path);
429 strfieldcat(path, temp);
431 print_device_chain(path);
437 printf("%s\n", udev_root);
442 printf("Usage: udevinfo [-anpqrdVh]\n"
443 " -q TYPE query database for the specified value:\n"
444 " 'name' name of device node\n"
445 " 'symlink' pointing to node\n"
446 " 'path' sysfs device path\n"
447 " 'all' all values\n"
449 " -p PATH sysfs device path used for query or chain\n"
450 " -n NAME node/symlink name used for query\n"
452 " -r print udev root\n"
453 " -a print all SYSFS_attributes along the device chain\n"
454 " -s print all sysfs devices with major/minor, physical device and bus\n"
455 " -V print udev version\n"
456 " -h print this help text\n"
461 int main(int argc, char *argv[], char *envp[])
465 logging_init("udevinfo");
467 /* initialize our configuration */
470 rc = process_options(argc, argv);