]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
mount-util: add new path_get_mnt_id() call that queries the mnt ID of a path
authorLennart Poettering <lennart@poettering.net>
Mon, 20 Nov 2017 15:05:41 +0000 (16:05 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 21 Nov 2017 10:37:12 +0000 (11:37 +0100)
This is a simple wrapper around name_to_handle_at_loop() and
fd_fdinfo_mnt_id() to query the mnt ID of a path. It uses
name_to_handle_at() where it can, and falls back to to
fd_fdinfo_mnt_id() where that doesn't work.

This is a best-effort thing of course, since neither name_to_handle_at()
nor the fdinfo logic work on all kernels.

src/basic/mount-util.c
src/basic/mount-util.h
src/test/test-mount-util.c

index 9fb96e6b6d7b31436b4cadb9119775012b2b8467..5f22bd68cec8758be2536e113a52d19a3e708e37 100644 (file)
@@ -302,6 +302,16 @@ int path_is_mount_point(const char *t, const char *root, int flags) {
         return fd_is_mount_point(fd, basename(t), flags);
 }
 
+int path_get_mnt_id(const char *path, int *ret) {
+        int r;
+
+        r = name_to_handle_at_loop(AT_FDCWD, path, NULL, ret, 0);
+        if (IN_SET(r, -EOPNOTSUPP, -ENOSYS, -EACCES, -EPERM)) /* kernel/fs don't support this, or seccomp blocks access */
+                return fd_fdinfo_mnt_id(AT_FDCWD, path, 0, ret);
+
+        return r;
+}
+
 int umount_recursive(const char *prefix, int flags) {
         bool again;
         int n = 0, r;
index 453bf9a0a5594550b00795a95da5b9b52437e7f0..a19b0d9c42101d8f74cce8f2ab63db52e4fd9e45 100644 (file)
@@ -32,6 +32,8 @@
 
 int name_to_handle_at_loop(int fd, const char *path, struct file_handle **ret_handle, int *ret_mnt_id, int flags);
 
+int path_get_mnt_id(const char *path, int *ret);
+
 int fd_is_mount_point(int fd, const char *filename, int flags);
 int path_is_mount_point(const char *path, const char *root, int flags);
 
index e2a0b4dfc150d56cb95588a3a42a70e3200f2800..5a93da1c0d75a8de8287850e8675007fdf9c8148 100644 (file)
 
 #include <sys/mount.h>
 
+#include "alloc-util.h"
+#include "def.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "hashmap.h"
 #include "log.h"
 #include "mount-util.h"
 #include "string-util.h"
@@ -42,6 +47,65 @@ static void test_mount_propagation_flags(const char *name, int ret, unsigned lon
         }
 }
 
+static void test_mnt_id(void) {
+        _cleanup_fclose_ FILE *f = NULL;
+        Hashmap *h;
+        Iterator i;
+        char *k;
+        void *p;
+        int r;
+
+        assert_se(f = fopen("/proc/self/mountinfo", "re"));
+        assert_se(h = hashmap_new(&string_hash_ops));
+
+        for (;;) {
+                _cleanup_free_ char *line = NULL, *path = NULL;
+                void *old_key;
+                int mnt_id;
+
+                r = read_line(f, LONG_LINE_MAX, &line);
+                if (r == 0)
+                        break;
+                assert_se(r > 0);
+
+                assert_se(sscanf(line, "%i %*s %*s %*s %ms", &mnt_id, &path) == 2);
+
+                /* Add all mount points and their ids to a hashtable, so that we filter out mount points that are
+                 * overmounted. For those we only care for the "upper" mount, since that's the only one
+                 * path_get_mnt_id() can determine. */
+
+                if (hashmap_remove2(h, path, &old_key))
+                        free(old_key);
+
+                assert_se(hashmap_put(h, path, INT_TO_PTR(mnt_id)) >= 0);
+                path = NULL;
+        }
+
+        HASHMAP_FOREACH_KEY(p, k, h, i) {
+                int mnt_id = PTR_TO_INT(p), mnt_id2;
+
+                r = path_get_mnt_id(k, &mnt_id2);
+                if (r == -EOPNOTSUPP) { /* kernel or file system too old? */
+                        log_debug("%s doesn't support mount IDs\n", k);
+                        continue;
+                }
+                if (IN_SET(r, -EACCES, -EPERM)) {
+                        log_debug("Can't access %s\n", k);
+                        continue;
+                }
+
+                log_debug("mnt id of %s is %i\n", k, mnt_id2);
+
+                assert_se(r >= 0);
+                assert_se(mnt_id == mnt_id2);
+        }
+
+        while ((k = hashmap_steal_first_key(h)))
+                free(k);
+
+        hashmap_free(h);
+}
+
 int main(int argc, char *argv[]) {
 
         log_set_max_level(LOG_DEBUG);
@@ -54,5 +118,7 @@ int main(int argc, char *argv[]) {
         test_mount_propagation_flags("xxxx", -EINVAL, 0);
         test_mount_propagation_flags(" ", -EINVAL, 0);
 
+        test_mnt_id();
+
         return 0;
 }