summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2022-01-22 00:10:09 +0900
committerGitHub <noreply@github.com>2022-01-22 00:10:09 +0900
commitac16a593cf4ecf8dd04b8be78fd2e8fd2fe55991 (patch)
treef7af170452e40fdd9ecd7aae67148fe0fd0fa25e
parenta07b9926060782ab21decdcb282ea3f39ed4f124 (diff)
parent7ec624147a41d80f8e492c9fe19a24e2cda58c25 (diff)
downloadsystemd-ac16a593cf4ecf8dd04b8be78fd2e8fd2fe55991.tar.gz
Merge pull request #22202 from mwilck/keep-links-02
udevadm info --cleanup-db: don't delete information for kept db entries
-rw-r--r--src/udev/udevadm-info.c68
1 files changed, 63 insertions, 5 deletions
diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c
index 740434bb41..018a52ada8 100644
--- a/src/udev/udevadm-info.c
+++ b/src/udev/udevadm-info.c
@@ -232,12 +232,14 @@ static void cleanup_dir(DIR *dir, mode_t mask, int depth) {
if (depth <= 0)
return;
+ assert(dir);
+
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;
@@ -254,6 +256,62 @@ 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).
+ * Returns true if the directory is empty after cleanup.
+ */
+static bool cleanup_dir_after_db_cleanup(DIR *dir, DIR *datadir) {
+ unsigned int kept = 0;
+
+ assert(dir && datadir);
+
+ FOREACH_DIRENT_ALL(dent, dir, break) {
+ struct stat data_stats, link_stats;
+
+ if (dot_or_dot_dot(dent->d_name))
+ continue;
+ if (fstatat(dirfd(dir), dent->d_name, &link_stats, AT_SYMLINK_NOFOLLOW) < 0) {
+ if (errno != ENOENT)
+ kept++;
+ continue;
+ }
+
+ if (fstatat(dirfd(datadir), dent->d_name, &data_stats, 0) < 0)
+ (void) unlinkat(dirfd(dir), dent->d_name,
+ S_ISDIR(link_stats.st_mode) ? AT_REMOVEDIR : 0);
+ else
+ /* The entry still exists under /run/udev/data */
+ kept++;
+ }
+
+ return kept == 0;
+}
+
+static void cleanup_dirs_after_db_cleanup(DIR *dir, DIR *datadir) {
+
+ assert(dir && 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;
@@ -263,11 +321,11 @@ 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)
@@ -275,7 +333,7 @@ static void cleanup_db(void) {
dir5 = opendir("/run/udev/watch");
if (dir5)
- cleanup_dir(dir5, 0, 1);
+ cleanup_dir_after_db_cleanup(dir5, dir1);
}
static int query_device(QueryType query, sd_device* device) {