]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/udev/udevadm-info.c
strv: make iterator in STRV_FOREACH() declaread in the loop
[thirdparty/systemd.git] / src / udev / udevadm-info.c
index 84f7794e86fb7b9ae5a0b0978d4d35b8b5da23f1..66ddf3a779db57a0e4aeea1f8dd021a71434c77d 100644 (file)
@@ -16,6 +16,7 @@
 #include "device-private.h"
 #include "device-util.h"
 #include "dirent-util.h"
+#include "errno-util.h"
 #include "fd-util.h"
 #include "sort-util.h"
 #include "static-destruct.h"
@@ -47,6 +48,8 @@ static const char *arg_export_prefix = NULL;
 static usec_t arg_wait_for_initialization_timeout = 0;
 
 static bool skip_attribute(const char *name) {
+        assert(name);
+
         /* Those are either displayed separately or should not be shown at all. */
         return STR_IN_SET(name,
                           "uevent",
@@ -66,6 +69,9 @@ typedef struct SysAttr {
 STATIC_DESTRUCTOR_REGISTER(arg_properties, strv_freep);
 
 static int sysattr_compare(const SysAttr *a, const SysAttr *b) {
+        assert(a);
+        assert(b);
+
         return strcmp(a->name, b->name);
 }
 
@@ -73,6 +79,9 @@ static int print_all_attributes(sd_device *device, bool is_parent) {
         _cleanup_free_ SysAttr *sysattrs = NULL;
         const char *name, *value;
         size_t n_items = 0;
+        int r;
+
+        assert(device);
 
         value = NULL;
         (void) sd_device_get_devpath(device, &value);
@@ -96,18 +105,22 @@ static int print_all_attributes(sd_device *device, bool is_parent) {
                 if (skip_attribute(name))
                         continue;
 
-                if (sd_device_get_sysattr_value(device, name, &value) < 0)
-                        continue;
+                r = sd_device_get_sysattr_value(device, name, &value);
+                if (r >= 0) {
+                        /* skip any values that look like a path */
+                        if (value[0] == '/')
+                                continue;
 
-                /* skip any values that look like a path */
-                if (value[0] == '/')
-                        continue;
+                        /* skip nonprintable attributes */
+                        len = strlen(value);
+                        while (len > 0 && isprint((unsigned char) value[len-1]))
+                                len--;
+                        if (len > 0)
+                                continue;
 
-                /* skip nonprintable attributes */
-                len = strlen(value);
-                while (len > 0 && isprint((unsigned char) value[len-1]))
-                        len--;
-                if (len > 0)
+                } else if (ERRNO_IS_PRIVILEGE(r))
+                        value = "(not readable)";
+                else
                         continue;
 
                 if (!GREEDY_REALLOC(sysattrs, n_items + 1))
@@ -134,6 +147,8 @@ static int print_device_chain(sd_device *device) {
         sd_device *child, *parent;
         int r;
 
+        assert(device);
+
         printf("\n"
                "Udevadm info starts with the device specified by the devpath and then\n"
                "walks up the chain of parent devices. It prints for every device\n"
@@ -159,6 +174,8 @@ static int print_record(sd_device *device) {
         const char *str, *val;
         int i;
 
+        assert(device);
+
         (void) sd_device_get_devpath(device, &str);
         printf("P: %s\n", str);
 
@@ -185,6 +202,8 @@ static int print_record(sd_device *device) {
 static int stat_device(const char *name, bool export, const char *prefix) {
         struct stat statbuf;
 
+        assert(name);
+
         if (stat(name, &statbuf) != 0)
                 return -errno;
 
@@ -224,7 +243,7 @@ static int export_devices(void) {
 }
 
 static void cleanup_dir(DIR *dir, mode_t mask, int depth) {
-        struct dirent *dent;
+        assert(dir);
 
         if (depth <= 0)
                 return;
@@ -232,9 +251,9 @@ static void cleanup_dir(DIR *dir, mode_t mask, int depth) {
         FOREACH_DIRENT_ALL(dent, dir, break) {
                 struct stat stats;
 
-                if (dent->d_name[0] == '.')
+                if (dot_or_dot_dot(dent->d_name))
                         continue;
-                if (fstatat(dirfd(dir), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) != 0)
+                if (fstatat(dirfd(dir), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) < 0)
                         continue;
                 if ((stats.st_mode & mask) != 0)
                         continue;
@@ -251,8 +270,55 @@ static void cleanup_dir(DIR *dir, mode_t mask, int depth) {
         }
 }
 
+/*
+ * Assume that dir is a directory with file names matching udev data base
+ * entries for devices in /run/udev/data (such as "b8:16"), and removes
+ * all files except those that haven't been deleted in /run/udev/data
+ * (i.e. they were skipped during db cleanup because of the db_persist flag).
+ */
+static void cleanup_dir_after_db_cleanup(DIR *dir, DIR *datadir) {
+        assert(dir);
+        assert(datadir);
+
+        FOREACH_DIRENT_ALL(dent, dir, break) {
+                if (dot_or_dot_dot(dent->d_name))
+                        continue;
+
+                if (faccessat(dirfd(datadir), dent->d_name, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
+                        /* The corresponding udev database file still exists.
+                         * Assuming the parsistent flag is set for the database. */
+                        continue;
+
+                (void) unlinkat(dirfd(dir), dent->d_name, 0);
+        }
+}
+
+static void cleanup_dirs_after_db_cleanup(DIR *dir, DIR *datadir) {
+        assert(dir);
+        assert(datadir);
+
+        FOREACH_DIRENT_ALL(dent, dir, break) {
+                struct stat stats;
+
+                if (dot_or_dot_dot(dent->d_name))
+                        continue;
+                if (fstatat(dirfd(dir), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) < 0)
+                        continue;
+                if (S_ISDIR(stats.st_mode)) {
+                        _cleanup_closedir_ DIR *dir2 = NULL;
+
+                        dir2 = fdopendir(openat(dirfd(dir), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
+                        if (dir2)
+                                cleanup_dir_after_db_cleanup(dir2, datadir);
+
+                        (void) unlinkat(dirfd(dir), dent->d_name, AT_REMOVEDIR);
+                } else
+                        (void) unlinkat(dirfd(dir), dent->d_name, 0);
+        }
+}
+
 static void cleanup_db(void) {
-        _cleanup_closedir_ DIR *dir1 = NULL, *dir2 = NULL, *dir3 = NULL, *dir4 = NULL, *dir5 = NULL;
+        _cleanup_closedir_ DIR *dir1 = NULL, *dir2 = NULL, *dir3 = NULL, *dir4 = NULL;
 
         dir1 = opendir("/run/udev/data");
         if (dir1)
@@ -260,19 +326,18 @@ static void cleanup_db(void) {
 
         dir2 = opendir("/run/udev/links");
         if (dir2)
-                cleanup_dir(dir2, 0, 2);
+                cleanup_dirs_after_db_cleanup(dir2, dir1);
 
         dir3 = opendir("/run/udev/tags");
         if (dir3)
-                cleanup_dir(dir3, 0, 2);
+                cleanup_dirs_after_db_cleanup(dir3, dir1);
 
         dir4 = opendir("/run/udev/static_node-tags");
         if (dir4)
                 cleanup_dir(dir4, 0, 2);
 
-        dir5 = opendir("/run/udev/watch");
-        if (dir5)
-                cleanup_dir(dir5, 0, 1);
+        /* Do not remove /run/udev/watch. It will be handled by udevd well on restart.
+         * And should not be removed by external program when udevd is running. */
 }
 
 static int query_device(QueryType query, sd_device* device) {
@@ -338,10 +403,10 @@ static int query_device(QueryType query, sd_device* device) {
 
         case QUERY_ALL:
                 return print_record(device);
-        }
 
-        assert_not_reached();
-        return 0;
+        default:
+                assert_not_reached();
+        }
 }
 
 static int help(void) {
@@ -519,7 +584,6 @@ int info_main(int argc, char *argv[], void *userdata) {
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                        "-x/--export or -P/--export-prefix cannot be used with --value");
 
-        char **p;
         STRV_FOREACH(p, devices) {
                 _cleanup_(sd_device_unrefp) sd_device *device = NULL;