/*
- * udevinfo.c - fetches stored device information or sysfs attributes
- *
- * Copyright (C) 2004-2005 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2004-2006 Kay Sievers <kay.sievers@vrfy.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
+#include <getopt.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include "udev.h"
}
#endif
-static void print_all_attributes(const char *devpath)
+static void print_all_attributes(const char *devpath, const char *key)
{
char path[PATH_SIZE];
DIR *dir;
dir = opendir(path);
if (dir != NULL) {
for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+ struct stat statbuf;
+ char filename[PATH_SIZE];
char *attr_value;
char value[NAME_SIZE];
size_t len;
+ if (dent->d_name[0] == '.')
+ continue;
+
+ strlcpy(filename, path, sizeof(filename));
+ strlcat(filename, "/", sizeof(filename));
+ strlcat(filename, dent->d_name, sizeof(filename));
+ if (lstat(filename, &statbuf) != 0)
+ continue;
+ if (S_ISLNK(statbuf.st_mode))
+ continue;
+
attr_value = sysfs_attr_get_value(devpath, dent->d_name);
if (attr_value == NULL)
continue;
continue;
}
- replace_untrusted_chars(value);
- printf(" SYSFS{%s}==\"%s\"\n", dent->d_name, value);
+ replace_chars(value, ALLOWED_CHARS_INPUT);
+ printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
}
}
printf("\n");
{
struct sysfs_device *dev;
- printf("\n"
- "udevinfo starts with the device the node belongs to and then walks up the\n"
- "device chain, to print for every device found, all possibly useful attributes\n"
- "in the udev key format.\n"
- "Only attributes within one device section may be used together in one rule,\n"
- "to match the device for which the node will be created.\n"
- "\n");
-
dev = sysfs_device_get(devpath);
if (dev == NULL)
return -1;
+ printf("\n"
+ "Udevinfo starts with the device specified by the devpath and then\n"
+ "walks up the chain of parent devices. It prints for every device\n"
+ "found, all possible attributes in the udev rules key format.\n"
+ "A rule to match, can be composed by the attributes of the device\n"
+ "and the attributes from one single parent device.\n"
+ "\n");
+
printf(" looking at device '%s':\n", dev->devpath);
- printf(" KERNEL==\"%s\"\n", dev->kernel_name);
+ printf(" KERNEL==\"%s\"\n", dev->kernel);
printf(" SUBSYSTEM==\"%s\"\n", dev->subsystem);
- print_all_attributes(dev->devpath);
+ printf(" DRIVER==\"%s\"\n", dev->driver);
+ print_all_attributes(dev->devpath, "ATTR");
/* walk up the chain of devices */
while (1) {
dev = sysfs_device_get_parent(dev);
if (dev == NULL)
break;
- printf(" looking at device '%s':\n", dev->devpath);
- printf(" ID==\"%s\"\n", dev->kernel_name);
- printf(" BUS==\"%s\"\n", dev->subsystem);
- printf(" DRIVER==\"%s\"\n", dev->driver);
+ printf(" looking at parent device '%s':\n", dev->devpath);
+ printf(" KERNELS==\"%s\"\n", dev->kernel);
+ printf(" SUBSYSTEMS==\"%s\"\n", dev->subsystem);
+ printf(" DRIVERS==\"%s\"\n", dev->driver);
- print_all_attributes(dev->devpath);
+ print_all_attributes(dev->devpath, "ATTRS");
}
return 0;
printf("N: %s\n", udev->name);
list_for_each_entry(name_loop, &udev->symlink_list, node)
printf("S: %s\n", name_loop->name);
+ if (udev->link_priority != 0)
+ printf("L: %i\n", udev->link_priority);
+ if (udev->partitions != 0)
+ printf("A:%u\n", udev->partitions);
+ if (udev->ignore_remove)
+ printf("R:%u\n", udev->ignore_remove);
list_for_each_entry(name_loop, &udev->env_list, node)
printf("E: %s\n", name_loop->name);
}
-static void export_name_devpath(struct udevice *udev) {
- printf("%s=%s/%s\n", udev->dev->devpath, udev_root, udev->name);
-}
-
-static void export_record(struct udevice *udev) {
- print_record(udev);
- printf("\n");
-}
-
-static void export_db(void fnct(struct udevice *udev)) {
+static void export_db(void) {
LIST_HEAD(name_list);
struct name_entry *name_loop;
list_for_each_entry(name_loop, &name_list, node) {
struct udevice *udev_db;
- udev_db = udev_device_init();
+ udev_db = udev_device_init(NULL);
if (udev_db == NULL)
continue;
if (udev_db_get_device(udev_db, name_loop->name) == 0)
- fnct(udev_db);
+ print_record(udev_db);
+ printf("\n");
udev_device_cleanup(udev_db);
}
name_list_cleanup(&name_list);
}
-static void print_help(void)
+static int lookup_device_by_name(struct udevice *udev, const char *name)
{
- fprintf(stderr, "Usage: udevinfo [-anpqrVh]\n"
- " -q TYPE query database for the specified value:\n"
- " 'name' name of device node\n"
- " 'symlink' pointing to node\n"
- " 'path' sysfs device path\n"
- " 'env' the device related imported environment\n"
- " 'all' all values\n"
- "\n"
- " -p PATH sysfs device path used for query or chain\n"
- " -n NAME node/symlink name used for query\n"
- "\n"
- " -r prepend to query result or print udev_root\n"
- " -a print all SYSFS_attributes along the device chain\n"
- " -e export the content of the udev database\n"
- " -V print udev version\n"
- " -h print this help text\n"
- "\n");
+ LIST_HEAD(name_list);
+ int count;
+ struct name_entry *device;
+ int rc = -1;
+
+ count = udev_db_get_devices_by_name(name, &name_list);
+ if (count <= 0)
+ goto out;
+
+ info("found %i devices for '%s'", count, name);
+
+ /* select the device that seems to match */
+ list_for_each_entry(device, &name_list, node) {
+ char filename[PATH_SIZE];
+ struct stat statbuf;
+
+ udev_device_init(udev);
+ if (udev_db_get_device(udev, device->name) != 0)
+ continue;
+ info("found db entry '%s'", device->name);
+
+ /* make sure, we don't get a link of a differnt device */
+ strlcpy(filename, udev_root, sizeof(filename));
+ strlcat(filename, "/", sizeof(filename));
+ strlcat(filename, name, sizeof(filename));
+ if (stat(filename, &statbuf) != 0)
+ continue;
+ if (major(udev->devt) > 0 && udev->devt != statbuf.st_rdev) {
+ info("skip '%s', dev_t doesn't match", udev->name);
+ continue;
+ }
+ rc = 0;
+ break;
+ }
+out:
+ name_list_cleanup(&name_list);
+ return rc;
}
int main(int argc, char *argv[], char *envp[])
{
- static const char short_options[] = "aden:p:q:rVh";
int option;
struct udevice *udev;
int root = 0;
+ static const struct option options[] = {
+ { "name", 1, NULL, 'n' },
+ { "path", 1, NULL, 'p' },
+ { "query", 1, NULL, 'q' },
+ { "attribute-walk", 0, NULL, 'a' },
+ { "export-db", 0, NULL, 'e' },
+ { "root", 0, NULL, 'r' },
+ { "version", 0, NULL, 1 }, /* -V outputs braindead format */
+ { "help", 0, NULL, 'h' },
+ {}
+ };
+
enum action_type {
ACTION_NONE,
ACTION_QUERY,
char path[PATH_SIZE] = "";
char name[PATH_SIZE] = "";
- char temp[PATH_SIZE];
struct name_entry *name_loop;
- char *pos;
int rc = 0;
logging_init("udevinfo");
-
udev_config_init();
sysfs_init();
- udev = udev_device_init();
+ udev = udev_device_init(NULL);
if (udev == NULL) {
rc = 1;
goto exit;
}
- /* get command line options */
while (1) {
- option = getopt(argc, argv, short_options);
+ option = getopt_long(argc, argv, "aen:p:q:rVh", options, NULL);
if (option == -1)
break;
dbg("option '%c'", option);
switch (option) {
case 'n':
- dbg("udev name: %s\n", optarg);
- strlcpy(name, optarg, sizeof(name));
+ /* remove /dev if given */
+ if (strncmp(optarg, udev_root, strlen(udev_root)) == 0)
+ strlcpy(name, &optarg[strlen(udev_root)+1], sizeof(name));
+ else
+ strlcpy(name, optarg, sizeof(name));
+ dbg("name: %s", name);
break;
case 'p':
- dbg("udev path: %s\n", optarg);
- /* remove sysfs mountpoint if not given */
+ /* remove /sys if given */
if (strncmp(optarg, sysfs_path, strlen(sysfs_path)) == 0)
strlcpy(path, &optarg[strlen(sysfs_path)], sizeof(path));
else
strlcpy(path, optarg, sizeof(path));
+ dbg("path: %s", path);
break;
case 'q':
- dbg("udev query: %s\n", optarg);
action = ACTION_QUERY;
if (strcmp(optarg, "name") == 0) {
query = QUERY_NAME;
case 'a':
action = ACTION_ATTRIBUTE_WALK;
break;
- case 'd':
- export_db(export_name_devpath);
- goto exit;
case 'e':
- export_db(export_record);
+ export_db();
+ goto exit;
+ case 1:
+ printf("%s\n", UDEV_VERSION);
goto exit;
case 'V':
printf("udevinfo, version %s\n", UDEV_VERSION);
goto exit;
case 'h':
- case '?':
+ printf("Usage: udevinfo OPTIONS\n"
+ " --query=<type> query database for the specified value:\n"
+ " name name of device node\n"
+ " symlink pointing to node\n"
+ " path sysfs device path\n"
+ " env the device related imported environment\n"
+ " all all values\n"
+ "\n"
+ " --path=<devpath> sysfs device path used for query or chain\n"
+ " --name=<name> node or symlink name used for query\n"
+ "\n"
+ " --root prepend to query result or print udev_root\n"
+ " --attribute-walk print all SYSFS_attributes along the device chain\n"
+ " --export-db export the content of the udev database\n"
+ " --help print this text\n"
+ "\n");
+ goto exit;
default:
- print_help();
goto exit;
}
}
/* run action */
switch (action) {
case ACTION_QUERY:
- /* need devpath or node/symlink name for query */
+ /* needs devpath or node/symlink name for query */
if (path[0] != '\0') {
- /* remove sysfs_path if given */
- if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
- pos = path + strlen(sysfs_path);
- } else {
- if (path[0] != '/') {
- /* prepend '/' if missing */
- strcpy(temp, "/");
- strlcpy(temp, path, sizeof(temp));
- pos = temp;
- } else {
- pos = path;
- }
- }
- if (udev_db_get_device(udev, pos) != 0) {
- fprintf(stderr, "no record for '%s' in database\n", pos);
+ if (udev_db_get_device(udev, path) != 0) {
+ fprintf(stderr, "no record for '%s' in database\n", path);
rc = 3;
goto exit;
}
} else if (name[0] != '\0') {
- char devpath[PATH_SIZE];
- int len;
-
- /* remove udev_root if given */
- len = strlen(udev_root);
- if (strncmp(name, udev_root, len) == 0) {
- pos = &name[len+1];
- } else
- pos = name;
-
- if (udev_db_lookup_name(pos, devpath, sizeof(devpath)) != 0) {
- fprintf(stderr, "no record for '%s' in database\n", pos);
- rc = 3;
+ if (lookup_device_by_name(udev, name) != 0) {
+ fprintf(stderr, "node name not found\n");
+ rc = 4;
goto exit;
}
- udev_db_get_device(udev, devpath);
} else {
- fprintf(stderr, "query needs device path(-p) or node name(-n) specified\n");
+ fprintf(stderr, "query needs --path or node --name specified\n");
rc = 4;
goto exit;
}
print_record(udev);
break;
default:
- print_help();
+ fprintf(stderr, "unknown query type\n");
break;
}
break;
case ACTION_ATTRIBUTE_WALK:
- if (path[0] == '\0') {
- fprintf(stderr, "attribute walk on device chain needs path(-p) specified\n");
- rc = 4;
+ if (path[0] != '\0') {
+ if (print_device_chain(path) != 0) {
+ fprintf(stderr, "no valid sysfs device found\n");
+ rc = 4;
+ goto exit;
+ }
+ } else if (name[0] != '\0') {
+ if (lookup_device_by_name(udev, name) != 0) {
+ fprintf(stderr, "node name not found\n");
+ rc = 4;
+ goto exit;
+ }
+ if (print_device_chain(udev->dev->devpath) != 0) {
+ fprintf(stderr, "no valid sysfs device found\n");
+ rc = 4;
+ goto exit;
+ }
+ } else {
+ fprintf(stderr, "attribute walk needs --path or node --name specified\n");
+ rc = 5;
goto exit;
- } else
- print_device_chain(path);
+ }
break;
case ACTION_ROOT:
printf("%s\n", udev_root);
break;
default:
- print_help();
+ fprintf(stderr, "missing option\n");
rc = 1;
break;
}