chiark / gitweb /
libudev: udev_device_get_sysattr_value() return syspath of custom links
[elogind.git] / udev / udevadm-info.c
index b743a1d642faa0f741e982c00c5a95b5ba3c24ef..f7e7e86b6a4a8f43cf9207b85f4176ab4874191c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2004-2009 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
 
 #include "udev.h"
 
-static void print_all_attributes(struct udev_device *device, const char *key)
+static bool skip_attribute(const char *name)
 {
-       struct udev *udev = udev_device_get_udev(device);
-       DIR *dir;
-       struct dirent *dent;
+       static const char const *skip[] = {
+               "uevent",
+               "dev",
+               "modalias",
+               "resource",
+               "driver",
+               "subsystem",
+               "module",
+       };
+       unsigned int i;
 
-       dir = opendir(udev_device_get_syspath(device));
-       if (dir != NULL) {
-               for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
-                       struct stat statbuf;
-                       const char *value;
-                       size_t len;
-
-                       if (dent->d_name[0] == '.')
-                               continue;
-
-                       if (strcmp(dent->d_name, "uevent") == 0)
-                               continue;
-                       if (strcmp(dent->d_name, "dev") == 0)
-                               continue;
-
-                       if (fstatat(dirfd(dir), dent->d_name, &statbuf, AT_SYMLINK_NOFOLLOW) != 0)
-                               continue;
-                       if (S_ISLNK(statbuf.st_mode))
-                               continue;
-
-                       value = udev_device_get_sysattr_value(device, dent->d_name);
-                       if (value == NULL)
-                               continue;
-                       dbg(udev, "attr '%s'='%s'(%zi)\n", dent->d_name, value, len);
-
-                       /* skip nonprintable attributes */
-                       len = strlen(value);
-                       while (len > 0 && isprint(value[len-1]))
-                               len--;
-                       if (len > 0) {
-                               dbg(udev, "attribute value of '%s' non-printable, skip\n", dent->d_name);
-                               continue;
-                       }
+       for (i = 0; i < ARRAY_SIZE(skip); i++)
+               if (strcmp(name, skip[i]) == 0)
+                       return true;
+       return false;
+}
 
-                       printf("    %s{%s}==\"%s\"\n", key, dent->d_name, value);
+static void print_all_attributes(struct udev_device *device, const char *key)
+{
+       struct udev *udev = udev_device_get_udev(device);
+       struct udev_list_entry *sysattr;
+
+       udev_list_entry_foreach(sysattr, udev_device_get_sysattr_list_entry(device)) {
+               const char *name;
+               const char *value;
+               size_t len;
+
+               name = udev_list_entry_get_name(sysattr);
+               if (skip_attribute(name))
+                       continue;
+
+               value = udev_device_get_sysattr_value(device, name);
+               if (value == NULL)
+                       continue;
+               dbg(udev, "attr '%s'='%s'\n", name, value);
+
+               /* skip any values that look like a path */
+               if (value[0] == '/')
+                       continue;
+
+               /* skip nonprintable attributes */
+               len = strlen(value);
+               while (len > 0 && isprint(value[len-1]))
+                       len--;
+               if (len > 0) {
+                       dbg(udev, "attribute value of '%s' non-printable, skip\n", name);
+                       continue;
                }
-               closedir(dir);
+
+               printf("    %s{%s}==\"%s\"\n", key, name, value);
        }
        printf("\n");
 }
@@ -142,18 +151,6 @@ static void print_record(struct udev_device *device)
        if (i != 0)
                printf("L: %i\n", i);
 
-       i = udev_device_get_num_fake_partitions(device);
-       if (i != 0)
-               printf("A:%u\n", i);
-
-       i = udev_device_get_ignore_remove(device);
-       if (i != 0)
-               printf("R:%u\n", i);
-
-       i = udev_device_get_watch_handle(device);
-       if (i >= 0)
-               printf("W:%u\n", i);
-
        udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
                len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
                printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
@@ -166,7 +163,7 @@ static void print_record(struct udev_device *device)
        printf("\n");
 }
 
-static int stat_device(const char *name, int export, const char *prefix)
+static int stat_device(const char *name, bool export, const char *prefix)
 {
        struct stat statbuf;
 
@@ -207,11 +204,86 @@ static int export_devices(struct udev *udev)
        return 0;
 }
 
-int udevadm_info(struct udev *udev, int argc, char *argv[])
+static void cleanup_dir(DIR *dir, mode_t mask, int depth)
+{
+       struct dirent *dent;
+
+       if (depth <= 0)
+               return;
+
+       for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+               struct stat stats;
+
+               if (dent->d_name[0] == '.')
+                       continue;
+               if (fstatat(dirfd(dir), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) != 0)
+                       continue;
+               if ((stats.st_mode & mask) != 0)
+                       continue;
+               if (S_ISDIR(stats.st_mode)) {
+                       DIR *dir2;
+
+                       dir2 = fdopendir(openat(dirfd(dir), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
+                       if (dir2 != NULL) {
+                               cleanup_dir(dir2, mask, depth-1);
+                               closedir(dir2);
+                       }
+                       unlinkat(dirfd(dir), dent->d_name, AT_REMOVEDIR);
+               } else {
+                       unlinkat(dirfd(dir), dent->d_name, 0);
+               }
+       }
+}
+
+static void cleanup_db(struct udev *udev)
+{
+       char filename[UTIL_PATH_SIZE];
+       DIR *dir;
+
+       util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/queue.bin", NULL);
+       unlink(filename);
+
+       util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/data", NULL);
+       dir = opendir(filename);
+       if (dir != NULL) {
+               cleanup_dir(dir, S_ISVTX, 1);
+               closedir(dir);
+       }
+
+       util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/links", NULL);
+       dir = opendir(filename);
+       if (dir != NULL) {
+               cleanup_dir(dir, 0, 2);
+               closedir(dir);
+       }
+
+       util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/tags", NULL);
+       dir = opendir(filename);
+       if (dir != NULL) {
+               cleanup_dir(dir, 0, 2);
+               closedir(dir);
+       }
+
+       util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/watch", NULL);
+       dir = opendir(filename);
+       if (dir != NULL) {
+               cleanup_dir(dir, 0, 1);
+               closedir(dir);
+       }
+
+       util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/firmware-missing", NULL);
+       dir = opendir(filename);
+       if (dir != NULL) {
+               cleanup_dir(dir, 0, 1);
+               closedir(dir);
+       }
+}
+
+static int uinfo(struct udev *udev, int argc, char *argv[])
 {
        struct udev_device *device = NULL;
-       int root = 0;
-       int export = 0;
+       bool root = 0;
+       bool export = 0;
        const char *export_prefix = NULL;
        char path[UTIL_PATH_SIZE];
        char name[UTIL_PATH_SIZE];
@@ -223,8 +295,10 @@ int udevadm_info(struct udev *udev, int argc, char *argv[])
                { "path", required_argument, NULL, 'p' },
                { "query", required_argument, NULL, 'q' },
                { "attribute-walk", no_argument, NULL, 'a' },
+               { "cleanup-db", no_argument, NULL, 'c' },
                { "export-db", no_argument, NULL, 'e' },
                { "root", no_argument, NULL, 'r' },
+               { "run", no_argument, NULL, 'R' },
                { "device-id-of-file", required_argument, NULL, 'd' },
                { "export", no_argument, NULL, 'x' },
                { "export-prefix", required_argument, NULL, 'P' },
@@ -246,15 +320,15 @@ int udevadm_info(struct udev *udev, int argc, char *argv[])
                QUERY_NAME,
                QUERY_PATH,
                QUERY_SYMLINK,
-               QUERY_ENV,
+               QUERY_PROPERTY,
                QUERY_ALL,
        } query = QUERY_NONE;
 
-       while (1) {
+       for (;;) {
                int option;
                struct stat statbuf;
 
-               option = getopt_long(argc, argv, "aed:n:p:q:rxPVh", options, NULL);
+               option = getopt_long(argc, argv, "aced:n:p:q:rxP:RVh", options, NULL);
                if (option == -1)
                        break;
 
@@ -317,34 +391,30 @@ int udevadm_info(struct udev *udev, int argc, char *argv[])
                        break;
                case 'q':
                        action = ACTION_QUERY;
-                       if (strcmp(optarg, "name") == 0) {
+                       if (strcmp(optarg, "property") == 0 || strcmp(optarg, "env") == 0) {
+                               query = QUERY_PROPERTY;
+                       } else if (strcmp(optarg, "name") == 0) {
                                query = QUERY_NAME;
-                               break;
-                       }
-                       if (strcmp(optarg, "symlink") == 0) {
+                       } else if (strcmp(optarg, "symlink") == 0) {
                                query = QUERY_SYMLINK;
-                               break;
-                       }
-                       if (strcmp(optarg, "path") == 0) {
+                       } else if (strcmp(optarg, "path") == 0) {
                                query = QUERY_PATH;
-                               break;
-                       }
-                       if (strcmp(optarg, "env") == 0) {
-                               query = QUERY_ENV;
-                               break;
-                       }
-                       if (strcmp(optarg, "all") == 0) {
+                       } else if (strcmp(optarg, "all") == 0) {
                                query = QUERY_ALL;
-                               break;
+                       } else {
+                               fprintf(stderr, "unknown query type\n");
+                               rc = 3;
+                               goto exit;
                        }
-                       fprintf(stderr, "unknown query type\n");
-                       rc = 3;
-                       goto exit;
+                       break;
                case 'r':
                        if (action == ACTION_NONE)
                                action = ACTION_ROOT;
-                       root = 1;
+                       root = true;
                        break;
+               case 'R':
+                       printf("%s\n", udev_get_run_path(udev));
+                       goto exit;
                case 'd':
                        action = ACTION_DEVICE_ID_FILE;
                        util_strscpy(name, sizeof(name), optarg);
@@ -355,8 +425,11 @@ int udevadm_info(struct udev *udev, int argc, char *argv[])
                case 'e':
                        export_devices(udev);
                        goto exit;
+               case 'c':
+                       cleanup_db(udev);
+                       goto exit;
                case 'x':
-                       export = 1;
+                       export = true;
                        break;
                case 'P':
                        export_prefix = optarg;
@@ -370,7 +443,7 @@ int udevadm_info(struct udev *udev, int argc, char *argv[])
                               "      name                     name of device node\n"
                               "      symlink                  pointing to node\n"
                               "      path                     sys device path\n"
-                              "      env                      the device related imported environment\n"
+                              "      property                 the device properties\n"
                               "      all                      all values\n"
                               "  --path=<syspath>           sys device path used for query or attribute walk\n"
                               "  --name=<name>              node or symlink name used for query or attribute walk\n"
@@ -378,10 +451,14 @@ int udevadm_info(struct udev *udev, int argc, char *argv[])
                               "  --attribute-walk           print all key matches while walking along the chain\n"
                               "                             of parent devices\n"
                               "  --device-id-of-file=<file> print major:minor of device containing this file\n"
+                              "  --export                   export key/value pairs\n"
+                              "  --export-prefix            export the key name with a prefix\n"
                               "  --export-db                export the content of the udev database\n"
+                              "  --cleanup-db               cleanup the udev database\n"
                               "  --help\n\n");
                        goto exit;
                default:
+                       rc = 1;
                        goto exit;
                }
        }
@@ -395,23 +472,24 @@ int udevadm_info(struct udev *udev, int argc, char *argv[])
                }
 
                switch(query) {
-               case QUERY_NAME:
+               case QUERY_NAME: {
+                       const char *node = udev_device_get_devnode(device);
+
+                       if (node == NULL) {
+                               fprintf(stderr, "no device node found\n");
+                               rc = 5;
+                               goto exit;
+                       }
+
                        if (root) {
                                printf("%s\n", udev_device_get_devnode(device));
                        } else {
-                               size_t len;
-                               const char *node;
-
-                               len = strlen(udev_get_dev_path(udev));
-                               node = udev_device_get_devnode(device);
-                               if (node == NULL) {
-                                       fprintf(stderr, "no device node found\n");
-                                       rc = 5;
-                                       goto exit;
-                               }
-                                       printf("%s\n", &udev_device_get_devnode(device)[len+1]);
+                               size_t len = strlen(udev_get_dev_path(udev));
+
+                               printf("%s\n", &udev_device_get_devnode(device)[len+1]);
                        }
                        break;
+               }
                case QUERY_SYMLINK:
                        list_entry = udev_device_get_devlinks_list_entry(device);
                        while (list_entry != NULL) {
@@ -432,10 +510,20 @@ int udevadm_info(struct udev *udev, int argc, char *argv[])
                case QUERY_PATH:
                        printf("%s\n", udev_device_get_devpath(device));
                        goto exit;
-               case QUERY_ENV:
+               case QUERY_PROPERTY:
                        list_entry = udev_device_get_properties_list_entry(device);
                        while (list_entry != NULL) {
-                               printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
+                               if (export) {
+                                       const char *prefix = export_prefix;
+
+                                       if (prefix == NULL)
+                                               prefix = "";
+                                       printf("%s%s='%s'\n", prefix,
+                                              udev_list_entry_get_name(list_entry),
+                                              udev_list_entry_get_value(list_entry));
+                               } else {
+                                       printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
+                               }
                                list_entry = udev_list_entry_get_next(list_entry);
                        }
                        break;
@@ -472,3 +560,9 @@ exit:
        udev_device_unref(device);
        return rc;
 }
+
+const struct udevadm_cmd udevadm_info = {
+       .name = "info",
+       .cmd = uinfo,
+       .help = "query sysfs or the udev database",
+};