From: Lennart Poettering Date: Mon, 20 Nov 2017 15:05:41 +0000 (+0100) Subject: mount-util: add new path_get_mnt_id() call that queries the mnt ID of a path X-Git-Tag: v236~150^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c2a986d5091af4e9c6f43695ecbfd7519f86e465;p=thirdparty%2Fsystemd.git mount-util: add new path_get_mnt_id() call that queries the mnt ID of a path 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. --- diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index 9fb96e6b6d7..5f22bd68cec 100644 --- a/src/basic/mount-util.c +++ b/src/basic/mount-util.c @@ -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; diff --git a/src/basic/mount-util.h b/src/basic/mount-util.h index 453bf9a0a55..a19b0d9c421 100644 --- a/src/basic/mount-util.h +++ b/src/basic/mount-util.h @@ -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); diff --git a/src/test/test-mount-util.c b/src/test/test-mount-util.c index e2a0b4dfc15..5a93da1c0d7 100644 --- a/src/test/test-mount-util.c +++ b/src/test/test-mount-util.c @@ -20,6 +20,11 @@ #include +#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; }