#include <string.h> #include <unistd.h> #include <sys/mount.h> #include <sys/stat.h> #include <stdio.h> static int tmpfs(const char *name) { return mount("none", name, "tmpfs", 0, NULL); } static int change(const char *name, int how) { return mount(NULL, name, NULL, how, NULL); } static int bind(const char *from, const char *to) { return mount(from, to, NULL, MS_BIND, NULL); } static _Bool exists(const char *name) { return access(name, F_OK) != -1; } void playground(void) { mkdir("/tmp/foo", 0700); tmpfs("/tmp/foo"); change("/tmp/foo", MS_PRIVATE); chdir("/tmp/foo"); } void cleanup(int fd) { close(fd); chdir("/tmp"); umount2("/tmp/foo", MNT_DETACH); rmdir("/tmp/foo"); } main() { playground(); mkdir("A", 0700); mkdir("A/subdir", 0700); mkdir("B", 0700); bind("A", "A"); change("A", MS_SHARED); int fd = open_tree(AT_FDCWD, "A", OPEN_TREE_CLONE); // this move_mount should fail (directory on top of non-directory) if (move_mount(fd, "", AT_FDCWD, "/dev/null", MOVE_MOUNT_F_EMPTY_PATH) == 0) { printf("unexpected success of first move_mount()\n"); cleanup(fd); return -1; } // this should propagate into detached tree tmpfs("A/subdir"); mkdir("A/subdir/foo", 0700); // move detached tree in, so we could check it if (move_mount(fd, "", AT_FDCWD, "B", MOVE_MOUNT_F_EMPTY_PATH) != 0) { printf("unexpected failure of the second move_mount()\n"); cleanup(fd); } if (!exists("B/subdir/foo")) { printf("failed to propagate into detached tree\n"); cleanup(fd); return -1; } printf("success\n"); cleanup(fd); return 0; }