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>
34
static void print_all_attributes(const char *devpath, const char *key)
40
strlcpy(path, sysfs_path, sizeof(path));
41
strlcat(path, devpath, sizeof(path));
45
for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
47
char filename[PATH_SIZE];
49
char value[NAME_SIZE];
52
if (dent->d_name[0] == '.')
55
if (strcmp(dent->d_name, "uevent") == 0)
57
if (strcmp(dent->d_name, "dev") == 0)
60
strlcpy(filename, path, sizeof(filename));
61
strlcat(filename, "/", sizeof(filename));
62
strlcat(filename, dent->d_name, sizeof(filename));
63
if (lstat(filename, &statbuf) != 0)
65
if (S_ISLNK(statbuf.st_mode))
68
attr_value = sysfs_attr_get_value(devpath, dent->d_name);
69
if (attr_value == NULL)
71
len = strlcpy(value, attr_value, sizeof(value));
72
if(len >= sizeof(value))
73
len = sizeof(value) - 1;
74
dbg("attr '%s'='%s'(%zi)\n", dent->d_name, value, len);
76
/* remove trailing newlines */
77
while (len && value[len-1] == '\n')
80
/* skip nonprintable attributes */
81
while (len && isprint(value[len-1]))
84
dbg("attribute value of '%s' non-printable, skip\n", dent->d_name);
88
printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
94
static int print_device_chain(const char *devpath)
96
struct sysfs_device *dev;
98
dev = sysfs_device_get(devpath);
103
"Udevinfo starts with the device specified by the devpath and then\n"
104
"walks up the chain of parent devices. It prints for every device\n"
105
"found, all possible attributes in the udev rules key format.\n"
106
"A rule to match, can be composed by the attributes of the device\n"
107
"and the attributes from one single parent device.\n"
110
printf(" looking at device '%s':\n", dev->devpath);
111
printf(" KERNEL==\"%s\"\n", dev->kernel);
112
printf(" SUBSYSTEM==\"%s\"\n", dev->subsystem);
113
printf(" DRIVER==\"%s\"\n", dev->driver);
114
print_all_attributes(dev->devpath, "ATTR");
116
/* walk up the chain of devices */
118
dev = sysfs_device_get_parent(dev);
121
printf(" looking at parent device '%s':\n", dev->devpath);
122
printf(" KERNELS==\"%s\"\n", dev->kernel);
123
printf(" SUBSYSTEMS==\"%s\"\n", dev->subsystem);
124
printf(" DRIVERS==\"%s\"\n", dev->driver);
126
print_all_attributes(dev->devpath, "ATTRS");
132
static void print_record(struct udevice *udev)
134
struct name_entry *name_loop;
136
printf("P: %s\n", udev->dev->devpath);
137
printf("N: %s\n", udev->name);
138
list_for_each_entry(name_loop, &udev->symlink_list, node)
139
printf("S: %s\n", name_loop->name);
140
if (udev->link_priority != 0)
141
printf("L: %i\n", udev->link_priority);
142
if (udev->partitions != 0)
143
printf("A:%u\n", udev->partitions);
144
if (udev->ignore_remove)
145
printf("R:%u\n", udev->ignore_remove);
146
list_for_each_entry(name_loop, &udev->env_list, node)
147
printf("E: %s\n", name_loop->name);
150
static void export_db(void) {
151
LIST_HEAD(name_list);
152
struct name_entry *name_loop;
154
udev_db_get_all_entries(&name_list);
155
list_for_each_entry(name_loop, &name_list, node) {
156
struct udevice *udev_db;
158
udev_db = udev_device_init(NULL);
161
if (udev_db_get_device(udev_db, name_loop->name) == 0)
162
print_record(udev_db);
164
udev_device_cleanup(udev_db);
166
name_list_cleanup(&name_list);
169
static int lookup_device_by_name(struct udevice *udev, const char *name)
171
LIST_HEAD(name_list);
173
struct name_entry *device;
176
count = udev_db_get_devices_by_name(name, &name_list);
180
info("found %i devices for '%s'\n", count, name);
182
/* select the device that seems to match */
183
list_for_each_entry(device, &name_list, node) {
184
char filename[PATH_SIZE];
187
udev_device_init(udev);
188
if (udev_db_get_device(udev, device->name) != 0)
190
info("found db entry '%s'\n", device->name);
192
/* make sure, we don't get a link of a differnt device */
193
strlcpy(filename, udev_root, sizeof(filename));
194
strlcat(filename, "/", sizeof(filename));
195
strlcat(filename, name, sizeof(filename));
196
if (stat(filename, &statbuf) != 0)
198
if (major(udev->devt) > 0 && udev->devt != statbuf.st_rdev) {
199
info("skip '%s', dev_t doesn't match\n", udev->name);
206
name_list_cleanup(&name_list);
210
static int stat_device(const char *name, int export, const char *prefix)
214
if (stat(name, &statbuf) != 0)
220
printf("%sMAJOR=%d\n"
222
prefix, major(statbuf.st_dev),
223
prefix, minor(statbuf.st_dev));
225
printf("%d %d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
229
int udevinfo(int argc, char *argv[], char *envp[])
232
struct udevice *udev;
235
const char *export_prefix = NULL;
237
static const struct option options[] = {
238
{ "name", 1, NULL, 'n' },
239
{ "path", 1, NULL, 'p' },
240
{ "query", 1, NULL, 'q' },
241
{ "attribute-walk", 0, NULL, 'a' },
242
{ "export-db", 0, NULL, 'e' },
243
{ "root", 0, NULL, 'r' },
244
{ "device-id-of-file", 1, NULL, 'd' },
245
{ "export", 0, NULL, 'x' },
246
{ "export-prefix", 1, NULL, 'P' },
247
{ "version", 0, NULL, 1 }, /* -V outputs braindead format */
248
{ "help", 0, NULL, 'h' },
255
ACTION_ATTRIBUTE_WALK,
257
ACTION_DEVICE_ID_FILE,
258
} action = ACTION_NONE;
267
} query = QUERY_NONE;
269
char path[PATH_SIZE] = "";
270
char name[PATH_SIZE] = "";
271
struct name_entry *name_loop;
274
logging_init("udevinfo");
278
udev = udev_device_init(NULL);
285
option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
289
dbg("option '%c'\n", option);
292
/* remove /dev if given */
293
if (strncmp(optarg, udev_root, strlen(udev_root)) == 0)
294
strlcpy(name, &optarg[strlen(udev_root)+1], sizeof(name));
296
strlcpy(name, optarg, sizeof(name));
297
remove_trailing_chars(name, '/');
298
dbg("name: %s\n", name);
301
/* remove /sys if given */
302
if (strncmp(optarg, sysfs_path, strlen(sysfs_path)) == 0)
303
strlcpy(path, &optarg[strlen(sysfs_path)], sizeof(path));
305
strlcpy(path, optarg, sizeof(path));
306
remove_trailing_chars(path, '/');
308
/* possibly resolve to real devpath */
309
if (sysfs_resolve_link(path, sizeof(path)) != 0) {
310
char temp[PATH_SIZE];
313
/* also check if the parent is a link */
314
strlcpy(temp, path, sizeof(temp));
315
pos = strrchr(temp, '/');
317
char tail[PATH_SIZE];
319
strlcpy(tail, pos, sizeof(tail));
321
if (sysfs_resolve_link(temp, sizeof(temp)) == 0) {
322
strlcpy(path, temp, sizeof(path));
323
strlcat(path, tail, sizeof(path));
327
dbg("path: %s\n", path);
330
action = ACTION_QUERY;
331
if (strcmp(optarg, "name") == 0) {
335
if (strcmp(optarg, "symlink") == 0) {
336
query = QUERY_SYMLINK;
339
if (strcmp(optarg, "path") == 0) {
343
if (strcmp(optarg, "env") == 0) {
347
if (strcmp(optarg, "all") == 0) {
351
fprintf(stderr, "unknown query type\n");
355
if (action == ACTION_NONE)
356
action = ACTION_ROOT;
360
action = ACTION_DEVICE_ID_FILE;
361
strlcpy(name, optarg, sizeof(name));
364
action = ACTION_ATTRIBUTE_WALK;
373
export_prefix = optarg;
376
printf("%s\n", UDEV_VERSION);
379
printf("udevinfo, version %s\n", UDEV_VERSION);
382
printf("Usage: udevadm info OPTIONS\n"
383
" --query=<type> query database for the specified value:\n"
384
" name name of device node\n"
385
" symlink pointing to node\n"
386
" path sysfs device path\n"
387
" env the device related imported environment\n"
389
" --path=<devpath> sysfs device path used for query or chain\n"
390
" --name=<name> node or symlink name used for query\n"
391
" --root prepend to query result or print udev_root\n"
392
" --attribute-walk print all key matches while walking along chain\n"
393
" of parent devices\n"
394
" --device-id-of-file=<file> print major/minor of underlying device\n"
395
" --export-db export the content of the udev database\n"
396
" --help print this text\n"
407
/* needs devpath or node/symlink name for query */
408
if (path[0] != '\0') {
409
if (udev_db_get_device(udev, path) != 0) {
410
fprintf(stderr, "no record for '%s' in database\n", path);
414
} else if (name[0] != '\0') {
415
if (lookup_device_by_name(udev, name) != 0) {
416
fprintf(stderr, "node name not found\n");
421
fprintf(stderr, "query needs --path or node --name specified\n");
429
printf("%s/%s\n", udev_root, udev->name);
431
printf("%s\n", udev->name);
434
list_for_each_entry(name_loop, &udev->symlink_list, node) {
435
char c = name_loop->node.next != &udev->symlink_list ? ' ' : '\n';
438
printf("%s/%s%c", udev_root, name_loop->name, c);
440
printf("%s%c", name_loop->name, c);
444
printf("%s\n", udev->dev->devpath);
447
list_for_each_entry(name_loop, &udev->env_list, node)
448
printf("%s\n", name_loop->name);
454
fprintf(stderr, "unknown query type\n");
458
case ACTION_ATTRIBUTE_WALK:
459
if (path[0] != '\0') {
460
if (print_device_chain(path) != 0) {
461
fprintf(stderr, "no valid sysfs device found\n");
465
} else if (name[0] != '\0') {
466
if (lookup_device_by_name(udev, name) != 0) {
467
fprintf(stderr, "node name not found\n");
471
if (print_device_chain(udev->dev->devpath) != 0) {
472
fprintf(stderr, "no valid sysfs device found\n");
477
fprintf(stderr, "attribute walk needs --path or node --name specified\n");
482
case ACTION_DEVICE_ID_FILE:
483
if (stat_device(name, export, export_prefix) != 0)
487
printf("%s\n", udev_root);
490
fprintf(stderr, "missing option\n");
496
udev_device_cleanup(udev);