criu/test/zdtm/static/mount_complex_sharing.c
Pavel Tikhomirov a0158e6927 zdtm: add MNTNS_ZDTM macro to fix initialization
With this macro we can easily declare struct mntns_zdtm variables with
all lists properly initiallized. Let's use it in mount_complex_sharing
as without it we can have segfault on error path when accessing
uninitialized list pointers.

Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
2023-04-15 21:17:21 -07:00

249 lines
6.5 KiB
C

#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <linux/limits.h>
#include "mountinfo.h"
#include "zdtmtst.h"
const char *test_doc = "Check complex sharing options for mounts";
const char *test_author = "Pavel Tikhomirov <ptikhomirov@virtuozzo.com>";
char *dirname = "mount_complex_sharing";
TEST_OPTION(dirname, string, "directory name", 1);
/*
* Description for creating a single file:
* path - path to create file in (relative to mount)
* dir - true if file is a directory
* content - if file is not a directory, this string is written into the file
*/
struct file {
char *path;
bool dir;
char *content;
};
/*
* Description for creating a single mount:
* mountpoint - path to create mount on (relative to dirname)
* bind - id of bind source if any or -1
* bind_root - root offset from bind source
* fstype - needed for non-binds, always tmpfs
* source - source for mounting
* flags - array of sharing options or mount flags applied after
* mounting (ending with -1)
* mounted - identifies implicitly propagated mounts
* files - array of files we need to create on mount (ending with zeroed file)
*/
struct mountinfo {
char *mountpoint;
int bind;
char *bind_root;
char *fstype;
char *source;
int flags[3];
bool mounted;
struct file files[10];
};
/* clang-format off */
struct mountinfo mounts[] = {
{"", -1, "", "tmpfs", "tmpfs-dirname", {MS_PRIVATE, -1}, false,
{
{"shared-bind-1", true},
{"shared-bind-2", true},
{"shared-bind-3", true},
{"shared-bind-4", true},
{"private-mnt", true},
{"shared-mnt", true},
{"slave-mnt", true},
{"slave-shared-mnt", true},
{"testfile", false, "TESTFILE"},
{NULL}
}
},
{"shared-bind-1", -1, "", "tmpfs", "tmpfs-shared-bind", {MS_SHARED, -1}, false,
{
{"prop-private", true},
{"prop-shared", true},
{"prop-slave", true},
{"prop-slave-shared", true},
{"prop-mount-flags", true},
{NULL}
}
},
{"shared-bind-2", 1, "", NULL, NULL, {-1}, false},
{"shared-bind-3", 1, "", NULL, NULL, {-1}, false},
{"shared-bind-4", 1, "", NULL, NULL, {-1}, false},
{"private-mnt", -1, "", "tmpfs", "tmpfs-mnt", {MS_PRIVATE, -1}, false,
{
{"subdir", true},
{NULL}
}
},
{"shared-mnt", 5, "", NULL, NULL, {MS_SHARED, -1}, false},
{"slave-mnt", 6, "", NULL, NULL, {MS_SLAVE, -1}, false},
{"slave-shared-mnt", 7, "", NULL, NULL, {MS_SHARED, -1}, false},
{"shared-bind-1/prop-private", 5, "subdir", NULL, NULL, {-1}, false},
{"shared-bind-1/prop-shared", 6, "subdir", NULL, NULL, {-1}, false},
{"shared-bind-1/prop-slave", 7, "subdir", NULL, NULL, {-1}, false},
{"shared-bind-1/prop-slave-shared", 8, "subdir", NULL, NULL, {-1}, false},
{"shared-bind-2/prop-private", -1, NULL, NULL, NULL, {MS_PRIVATE, -1}, true},
{"shared-bind-2/prop-shared", -1, NULL, NULL, NULL, {MS_PRIVATE, -1}, true},
{"shared-bind-2/prop-slave", -1, NULL, NULL, NULL, {MS_PRIVATE, -1}, true},
{"shared-bind-2/prop-slave-shared", -1, NULL, NULL, NULL, {MS_PRIVATE, -1}, true},
{"shared-bind-3/prop-private", -1, NULL, NULL, NULL, {MS_SLAVE, -1}, true},
{"shared-bind-3/prop-shared", -1, NULL, NULL, NULL, {MS_SLAVE, -1}, true},
{"shared-bind-3/prop-slave", -1, NULL, NULL, NULL, {MS_SLAVE, -1}, true},
{"shared-bind-3/prop-slave-shared", -1, NULL, NULL, NULL, {MS_SLAVE, -1}, true},
{"shared-bind-4/prop-private", -1, NULL, NULL, NULL, {MS_PRIVATE, MS_SHARED, -1}, true},
{"shared-bind-4/prop-shared", -1, NULL, NULL, NULL, {MS_PRIVATE, MS_SHARED, -1}, true},
{"shared-bind-4/prop-slave", -1, NULL, NULL, NULL, {MS_PRIVATE, MS_SHARED, -1}, true},
{"shared-bind-4/prop-slave-shared", -1, NULL, NULL, NULL, {MS_PRIVATE, MS_SHARED, -1}, true},
{"shared-bind-1/prop-mount-flags", 5, "subdir", NULL, NULL, {MS_RDONLY|MS_REMOUNT|MS_BIND, -1}, false},
{"shared-bind-2/prop-mount-flags", -1, NULL, NULL, NULL, {MS_RDONLY|MS_REMOUNT|MS_BIND, -1}, true},
{"shared-bind-3/prop-mount-flags", -1, NULL, NULL, NULL, {-1}, true},
{"shared-bind-4/prop-mount-flags", -1, NULL, NULL, NULL, {-1}, true},
};
/* clang-format on */
static int fill_content(struct mountinfo *mi)
{
struct file *file = &mi->files[0];
char path[PATH_MAX];
while (file->path != NULL) {
snprintf(path, sizeof(path), "%s/%s/%s", dirname, mi->mountpoint, file->path);
if (file->dir) {
test_msg("Mkdir %s\n", path);
if (mkdir(path, 0700)) {
pr_perror("Failed to create dir %s", path);
return -1;
}
} else {
int fd, len = strlen(file->content);
test_msg("Create file %s with content %s\n", path, file->content);
fd = open(path, O_WRONLY | O_CREAT, 0777);
if (fd < 0) {
pr_perror("Failed to create file %s", path);
return -1;
}
if (write(fd, file->content, len) != len) {
pr_perror("Failed to write %s to file %s", file->content, path);
close(fd);
return -1;
}
close(fd);
}
file++;
}
return 0;
}
static int mount_one(struct mountinfo *mi)
{
char source[PATH_MAX], target[PATH_MAX];
int *flags = mi->flags, mflags = 0;
char *fstype = NULL;
test_msg("Mounting %s %d %s %s %d\n", mi->mountpoint, mi->bind, mi->fstype, mi->source, mi->mounted);
snprintf(target, sizeof(target), "%s/%s", dirname, mi->mountpoint);
if (mi->mounted)
goto apply_flags;
if (mi->bind != -1) {
snprintf(source, sizeof(source), "%s/%s/%s", dirname, mounts[mi->bind].mountpoint, mi->bind_root);
fstype = NULL;
mflags = MS_BIND;
} else {
snprintf(source, sizeof(source), "%s", mi->source);
fstype = mi->fstype;
}
if (mount(source, target, fstype, mflags, NULL)) {
pr_perror("Failed to mount %s %s %s", source, target, fstype);
return -1;
}
if (fill_content(mi))
return -1;
apply_flags:
while (flags[0] != -1) {
test_msg("Making mount %s 0x%x\n", target, flags[0]);
if (mount(NULL, target, NULL, flags[0], NULL)) {
pr_perror("Failed to make mount %s 0x%x", target, flags[0]);
return -1;
}
flags++;
}
return 0;
}
static int mount_loop(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(mounts); i++) {
if (mount_one(&mounts[i]))
return 1;
}
return 0;
}
int main(int argc, char **argv)
{
MNTNS_ZDTM(mntns_before);
MNTNS_ZDTM(mntns_after);
int ret = 1;
test_init(argc, argv);
if (mkdir(dirname, 0700) && errno != EEXIST) {
pr_perror("Failed to create %s", dirname);
goto err;
}
if (mount_loop())
goto err;
if (mntns_parse_mountinfo(&mntns_before))
goto err;
test_daemon();
test_waitsig();
if (mntns_parse_mountinfo(&mntns_after))
goto err;
if (mntns_compare(&mntns_before, &mntns_after))
goto err;
pass();
ret = 0;
err:
mntns_free_all(&mntns_before);
mntns_free_all(&mntns_after);
if (ret)
fail();
return ret;
}