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;
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);
#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"
}
}
+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);
test_mount_propagation_flags("xxxx", -EINVAL, 0);
test_mount_propagation_flags(" ", -EINVAL, 0);
+ test_mnt_id();
+
return 0;
}