chiark / gitweb /
tmpfiles: --clean -- check for bind mounts of the same filesystem and skip them
authorKay Sievers <kay@vrfy.org>
Wed, 13 Mar 2013 12:12:36 +0000 (13:12 +0100)
committerKay Sievers <kay@vrfy.org>
Wed, 13 Mar 2013 12:16:10 +0000 (13:16 +0100)
TODO
src/tmpfiles/tmpfiles.c

diff --git a/TODO b/TODO
index 95a806b..f1a0bcf 100644 (file)
--- a/TODO
+++ b/TODO
@@ -78,8 +78,6 @@ Features:
 
 * remove any syslog support from log.c -- we probably can't do this before split-off udev is gone for good
 
-* tmpfiles: when traversing the tree, check for bind mount points with nametohandle()
-
 * fedora: connect the timer units of a service to the service via Also= in [Install], and maybe introduce timers.target
 
 * fedora: F20: go timer units all the way, leave cron.daily for cron
index b93d898..4a76a2f 100644 (file)
@@ -213,6 +213,42 @@ static bool unix_socket_alive(const char *fn) {
         return true;
 }
 
+static int dir_is_mount_point(DIR *d, const char *subdir) {
+        struct file_handle *h;
+        int mount_id_parent, mount_id;
+        int r_p, r;
+
+        h = alloca(MAX_HANDLE_SZ);
+
+        h->handle_bytes = MAX_HANDLE_SZ;
+        r_p = name_to_handle_at(dirfd(d), ".", h, &mount_id_parent, 0);
+        if (r_p < 0)
+                r_p = -errno;
+
+        h->handle_bytes = MAX_HANDLE_SZ;
+        r = name_to_handle_at(dirfd(d), subdir, h, &mount_id, 0);
+        if (r < 0)
+                r = -errno;
+
+        /* got no handle; make no assumptions, return error */
+        if (r_p < 0 && r < 0)
+                return r_p;
+
+        /* got both handles; if they differ, it is a mount point */
+        if (r_p >= 0 && r >= 0)
+                return mount_id_parent != mount_id;
+
+        /* got only one handle; assume different mount points if one
+         * of both queries was not supported by the filesystem */
+        if (r_p == -ENOSYS || r_p == -ENOTSUP || r == -ENOSYS || r == -ENOTSUP)
+                return true;
+
+        /* return error */
+        if (r_p < 0)
+                return r_p;
+        return r;
+}
+
 static int dir_cleanup(
                 Item *i,
                 const char *p,
@@ -252,6 +288,12 @@ static int dir_cleanup(
                 if (s.st_dev != rootdev)
                         continue;
 
+                /* Try to detect bind mounts of the same filesystem instance; they
+                 * do not differ in device major/minors. This type of query is not
+                 * supported on all kernels or filesystem types though. */
+                if (S_ISDIR(s.st_mode) && dir_is_mount_point(d, dent->d_name) > 0)
+                        continue;
+
                 /* Do not delete read-only files owned by root */
                 if (s.st_uid == 0 && !(s.st_mode & S_IWUSR))
                         continue;