#include <dirent.h>
#include <errno.h>
#include <getopt.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include "udev.h"
-
-#ifdef USE_LOG
-void log_message (int priority, const char *format, ...)
-{
- va_list args;
-
- if (priority > udev_log_priority)
- return;
-
- va_start(args, format);
- vsyslog(priority, format, args);
- va_end(args);
-}
-#endif
-
static void print_all_attributes(const char *devpath, const char *key)
{
char path[PATH_SIZE];
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;
+
+ if (strcmp(dent->d_name, "uevent") == 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;
len = strlcpy(value, attr_value, sizeof(value));
+ if(len >= sizeof(value))
+ len = sizeof(value) - 1;
dbg("attr '%s'='%s'(%zi)", dent->d_name, value, len);
/* remove trailing newlines */
continue;
}
- replace_untrusted_chars(value);
+ replace_chars(value, ALLOWED_CHARS_INPUT);
printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
}
}
{
struct sysfs_device *dev;
+ 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"
"and the attributes from one single parent device.\n"
"\n");
- dev = sysfs_device_get(devpath);
- if (dev == NULL)
- return -1;
-
printf(" looking at device '%s':\n", dev->devpath);
printf(" KERNEL==\"%s\"\n", dev->kernel);
printf(" SUBSYSTEM==\"%s\"\n", dev->subsystem);
break;
printf(" looking at parent device '%s':\n", dev->devpath);
printf(" KERNELS==\"%s\"\n", dev->kernel);
- printf(" SUBSYTEMS==\"%s\"\n", dev->subsystem);
+ printf(" SUBSYSTEMS==\"%s\"\n", dev->subsystem);
printf(" DRIVERS==\"%s\"\n", dev->driver);
print_all_attributes(dev->devpath, "ATTRS");
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);
}
-int main(int argc, char *argv[], char *envp[])
+static int lookup_device_by_name(struct udevice *udev, const char *name)
+{
+ 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;
+}
+
+static int stat_device(const char *name)
+{
+ struct stat statbuf;
+
+ if (stat(name, &statbuf) != 0)
+ return -1;
+
+ printf("%d %d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
+ return 0;
+}
+
+int udevinfo(int argc, char *argv[], char *envp[])
{
int option;
struct udevice *udev;
int root = 0;
- struct option options[] = {
+ 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, 'V' },
+ { "device-id-of-file", 1, NULL, 'd' },
+ { "version", 0, NULL, 1 }, /* -V outputs braindead format */
{ "help", 0, NULL, 'h' },
{}
};
ACTION_QUERY,
ACTION_ATTRIBUTE_WALK,
ACTION_ROOT,
+ ACTION_DEVICE_ID_FILE,
} action = ACTION_NONE;
enum query_type {
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_long(argc, argv, "aden:p:q:rVh", options, NULL);
+ option = getopt_long(argc, argv, "aed:n:p:q:rVh", options, NULL);
if (option == -1)
break;
strlcpy(name, &optarg[strlen(udev_root)+1], sizeof(name));
else
strlcpy(name, optarg, sizeof(name));
- dbg("name: %s\n", name);
+ remove_trailing_chars(name, '/');
+ dbg("name: %s", name);
break;
case 'p':
/* remove /sys if given */
strlcpy(path, &optarg[strlen(sysfs_path)], sizeof(path));
else
strlcpy(path, optarg, sizeof(path));
- dbg("path: %s\n", path);
+ remove_trailing_chars(path, '/');
+
+ /* possibly resolve to real devpath */
+ if (sysfs_resolve_link(path, sizeof(path)) != 0) {
+ char temp[PATH_SIZE];
+ char *pos;
+
+ /* also check if the parent is a link */
+ strlcpy(temp, path, sizeof(temp));
+ pos = strrchr(temp, '/');
+ if (pos != 0) {
+ char tail[PATH_SIZE];
+
+ strlcpy(tail, pos, sizeof(tail));
+ pos[0] = '\0';
+ if (sysfs_resolve_link(temp, sizeof(temp)) == 0) {
+ strlcpy(path, temp, sizeof(path));
+ strlcat(path, tail, 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;
action = ACTION_ROOT;
root = 1;
break;
+ case 'd':
+ action = ACTION_DEVICE_ID_FILE;
+ strlcpy(name, optarg, sizeof(name));
+ break;
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':
- 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"
- " --verision print udev version\n"
- " --help print this text\n"
+ printf("Usage: udevadm info 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"
+ " --path=<devpath> sysfs device path used for query or chain\n"
+ " --name=<name> node or symlink name used for query\n"
+ " --root prepend to query result or print udev_root\n"
+ " --attribute-walk print all key matches while walking along chain\n"
+ " of parent devices\n"
+ " --device-id-of-file=<file> print major/minor of underlying device\n"
+ " --export-db export the content of the udev database\n"
+ " --help print this text\n"
"\n");
goto exit;
default:
goto exit;
}
} else if (name[0] != '\0') {
- char devpath[PATH_SIZE];
-
- if (udev_db_lookup_name(name, devpath, sizeof(devpath)) != 0) {
+ 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 --path or node --name specified\n");
rc = 4;
printf("%s\n", udev->name);
break;
case QUERY_SYMLINK:
- if (list_empty(&udev->symlink_list))
- goto exit;
- if (root)
- list_for_each_entry(name_loop, &udev->symlink_list, node)
- printf("%s/%s ", udev_root, name_loop->name);
- else
- list_for_each_entry(name_loop, &udev->symlink_list, node)
- printf("%s ", name_loop->name);
- printf("\n");
+ list_for_each_entry(name_loop, &udev->symlink_list, node) {
+ char c = name_loop->node.next != &udev->symlink_list ? ' ' : '\n';
+
+ if (root)
+ printf("%s/%s%c", udev_root, name_loop->name, c);
+ else
+ printf("%s%c", name_loop->name, c);
+ }
break;
case QUERY_PATH:
printf("%s\n", udev->dev->devpath);
break;
case ACTION_ATTRIBUTE_WALK:
if (path[0] != '\0') {
- print_device_chain(path);
+ if (print_device_chain(path) != 0) {
+ fprintf(stderr, "no valid sysfs device found\n");
+ rc = 4;
+ goto exit;
+ }
} else if (name[0] != '\0') {
- char devpath[PATH_SIZE];
-
- if (udev_db_lookup_name(name, devpath, sizeof(devpath)) != 0) {
+ if (lookup_device_by_name(udev, name) != 0) {
fprintf(stderr, "node name not found\n");
rc = 4;
goto exit;
}
- print_device_chain(devpath);
+ 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;
}
break;
+ case ACTION_DEVICE_ID_FILE:
+ if (stat_device(name) != 0)
+ rc = 6;
+ break;
case ACTION_ROOT:
printf("%s\n", udev_root);
break;