#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; } int 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"); } int setup(void) { int fd; playground(); mkdir("A", 0700); mkdir("B", 0700); mkdir("C", 0700); tmpfs("A"); change("A", MS_SHARED); bind("A", "B"); change("B", MS_SLAVE); change("B", MS_SHARED); bind("B", "C"); change("C", MS_SLAVE); mkdir("A/foo", 0700); mkdir("A/subdir", 0700); fd = open_tree(AT_FDCWD, "B", OPEN_TREE_CLONE); change("B", MS_PRIVATE); return fd; } main() { int fd; fd = setup(); bind("B", "A/subdir"); printf("bind propagated to C: %s\n", exists("C/subdir/foo") ? "yes" : "no"); cleanup(fd); fd = setup(); move_mount(AT_FDCWD, "B", AT_FDCWD, "A/subdir", MOVE_MOUNT_F_EMPTY_PATH); printf("move_mount propagated to C: %s\n", exists("C/subdir/foo") ? "yes" : "no"); cleanup(fd); fd = setup(); move_mount(fd, "", AT_FDCWD, "A/subdir", MOVE_MOUNT_F_EMPTY_PATH); printf("move_mount (fd) propagated to C: %s\n", exists("C/subdir/foo") ? "yes" : "no"); cleanup(fd); return 0; }