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_chars(value
, ALLOWED_CHARS_INPUT
);
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 if (udev
->link_priority
!= 0)
150 printf("L: %i\n", udev
->link_priority
);
151 if (udev
->partitions
!= 0)
152 printf("A:%u\n", udev
->partitions
);
153 if (udev
->ignore_remove
)
154 printf("R:%u\n", udev
->ignore_remove
);
155 list_for_each_entry(name_loop
, &udev
->env_list
, node
)
156 printf("E: %s\n", name_loop
->name
);
159 static void export_db(void) {
160 LIST_HEAD(name_list
);
161 struct name_entry
*name_loop
;
163 udev_db_get_all_entries(&name_list
);
164 list_for_each_entry(name_loop
, &name_list
, node
) {
165 struct udevice
*udev_db
;
167 udev_db
= udev_device_init(NULL
);
170 if (udev_db_get_device(udev_db
, name_loop
->name
) == 0)
171 print_record(udev_db
);
173 udev_device_cleanup(udev_db
);
175 name_list_cleanup(&name_list
);
178 static int lookup_device_by_name(struct udevice
*udev
, const char *name
)
180 LIST_HEAD(name_list
);
182 struct name_entry
*device
;
185 count
= udev_db_get_devices_by_name(name
, &name_list
);
189 info("found %i devices for '%s'", count
, name
);
191 /* select the device that seems to match */
192 list_for_each_entry(device
, &name_list
, node
) {
193 char filename
[PATH_SIZE
];
196 udev_device_init(udev
);
197 if (udev_db_get_device(udev
, device
->name
) != 0)
199 info("found db entry '%s'", device
->name
);
201 /* make sure, we don't get a link of a differnt device */
202 strlcpy(filename
, udev_root
, sizeof(filename
));
203 strlcat(filename
, "/", sizeof(filename
));
204 strlcat(filename
, name
, sizeof(filename
));
205 if (stat(filename
, &statbuf
) != 0)
207 if (major(udev
->devt
) > 0 && udev
->devt
!= statbuf
.st_rdev
) {
208 info("skip '%s', dev_t doesn't match", udev
->name
);
215 name_list_cleanup(&name_list
);
219 int main(int argc
, char *argv
[], char *envp
[])
222 struct udevice
*udev
;
225 static const struct option options
[] = {
226 { "name", 1, NULL
, 'n' },
227 { "path", 1, NULL
, 'p' },
228 { "query", 1, NULL
, 'q' },
229 { "attribute-walk", 0, NULL
, 'a' },
230 { "export-db", 0, NULL
, 'e' },
231 { "root", 0, NULL
, 'r' },
232 { "version", 0, NULL
, 1 }, /* -V outputs braindead format */
233 { "help", 0, NULL
, 'h' },
240 ACTION_ATTRIBUTE_WALK
,
242 } action
= ACTION_NONE
;
251 } query
= QUERY_NONE
;
253 char path
[PATH_SIZE
] = "";
254 char name
[PATH_SIZE
] = "";
255 struct name_entry
*name_loop
;
258 logging_init("udevinfo");
262 udev
= udev_device_init(NULL
);
269 option
= getopt_long(argc
, argv
, "aen:p:q:rVh", options
, NULL
);
273 dbg("option '%c'", option
);
276 /* remove /dev if given */
277 if (strncmp(optarg
, udev_root
, strlen(udev_root
)) == 0)
278 strlcpy(name
, &optarg
[strlen(udev_root
)+1], sizeof(name
));
280 strlcpy(name
, optarg
, sizeof(name
));
281 dbg("name: %s", name
);
284 /* remove /sys if given */
285 if (strncmp(optarg
, sysfs_path
, strlen(sysfs_path
)) == 0)
286 strlcpy(path
, &optarg
[strlen(sysfs_path
)], sizeof(path
));
288 strlcpy(path
, optarg
, sizeof(path
));
289 dbg("path: %s", path
);
292 action
= ACTION_QUERY
;
293 if (strcmp(optarg
, "name") == 0) {
297 if (strcmp(optarg
, "symlink") == 0) {
298 query
= QUERY_SYMLINK
;
301 if (strcmp(optarg
, "path") == 0) {
305 if (strcmp(optarg
, "env") == 0) {
309 if (strcmp(optarg
, "all") == 0) {
313 fprintf(stderr
, "unknown query type\n");
317 if (action
== ACTION_NONE
)
318 action
= ACTION_ROOT
;
322 action
= ACTION_ATTRIBUTE_WALK
;
328 printf("%s\n", UDEV_VERSION
);
331 printf("udevinfo, version %s\n", UDEV_VERSION
);
334 printf("Usage: udevinfo OPTIONS\n"
335 " --query=<type> query database for the specified value:\n"
336 " name name of device node\n"
337 " symlink pointing to node\n"
338 " path sysfs device path\n"
339 " env the device related imported environment\n"
342 " --path=<devpath> sysfs device path used for query or chain\n"
343 " --name=<name> node or symlink name used for query\n"
345 " --root prepend to query result or print udev_root\n"
346 " --attribute-walk print all SYSFS_attributes along the device chain\n"
347 " --export-db export the content of the udev database\n"
348 " --help print this text\n"
359 /* needs devpath or node/symlink name for query */
360 if (path
[0] != '\0') {
361 if (udev_db_get_device(udev
, path
) != 0) {
362 fprintf(stderr
, "no record for '%s' in database\n", path
);
366 } else if (name
[0] != '\0') {
367 if (lookup_device_by_name(udev
, name
) != 0) {
368 fprintf(stderr
, "node name not found\n");
373 fprintf(stderr
, "query needs --path or node --name specified\n");
381 printf("%s/%s\n", udev_root
, udev
->name
);
383 printf("%s\n", udev
->name
);
386 if (list_empty(&udev
->symlink_list
))
389 list_for_each_entry(name_loop
, &udev
->symlink_list
, node
)
390 printf("%s/%s ", udev_root
, name_loop
->name
);
392 list_for_each_entry(name_loop
, &udev
->symlink_list
, node
)
393 printf("%s ", name_loop
->name
);
397 printf("%s\n", udev
->dev
->devpath
);
400 list_for_each_entry(name_loop
, &udev
->env_list
, node
)
401 printf("%s\n", name_loop
->name
);
407 fprintf(stderr
, "unknown query type\n");
411 case ACTION_ATTRIBUTE_WALK
:
412 if (path
[0] != '\0') {
413 if (print_device_chain(path
) != 0) {
414 fprintf(stderr
, "no valid sysfs device found\n");
418 } else if (name
[0] != '\0') {
419 if (lookup_device_by_name(udev
, name
) != 0) {
420 fprintf(stderr
, "node name not found\n");
424 if (print_device_chain(udev
->dev
->devpath
) != 0) {
425 fprintf(stderr
, "no valid sysfs device found\n");
430 fprintf(stderr
, "attribute walk needs --path or node --name specified\n");
436 printf("%s\n", udev_root
);
439 fprintf(stderr
, "missing option\n");
445 udev_device_cleanup(udev
);