diff options
author | Kay Sievers <kay@vrfy.org> | 2013-03-13 13:12:36 +0100 |
---|---|---|
committer | Kay Sievers <kay@vrfy.org> | 2013-03-13 13:16:10 +0100 |
commit | 99d680acf192a7193c3de73b525ffbc24c25cca8 (patch) | |
tree | 17a4103b70ee61a145c8e0cd86ba289c9037d2a1 | |
parent | 24a988e9aa17a476cb5381e2334aaa2a9972ddd2 (diff) |
tmpfiles: --clean -- check for bind mounts of the same filesystem and skip them
-rw-r--r-- | TODO | 2 | ||||
-rw-r--r-- | src/tmpfiles/tmpfiles.c | 42 |
2 files changed, 42 insertions, 2 deletions
@@ -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 diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index b93d8988fc..4a76a2f778 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -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; |