diff --git a/assertions/Makefile b/assertions/Makefile index 4028483..187fcd6 100644 --- a/assertions/Makefile +++ b/assertions/Makefile @@ -14,11 +14,16 @@ SRC_NAMESPACES_FS_CLONE=$(UNITY_ROOT)/src/unity.c namespaces/fs/TestClone.c test TARGET_NAMESPACES_FS_UNSHARE=target/test_namespaces_fs_unshare TARGET_NAMESPACES_FS_CLONE=target/test_namespaces_fs_clone +SRC_NAMESPACES_FILES_CLONE=$(UNITY_ROOT)/src/unity.c namespaces/files/TestClone.c test_runners/namespaces_files_TestClone_Runner.c + +TARGET_NAMESPACES_FILES_CLONE=target/test_namespaces_files_clone + all: clean default -default: $(SRC_NAMESPACES_FS_UNSHARE) $(SRC_NAMESPACES_FS_CLONE) +default: $(SRC_NAMESPACES_FS_UNSHARE) $(SRC_NAMESPACES_FS_CLONE) $(SRC_NAMESPACES_FILES_CLONE) $(C_COMPILER) $(CFLAGS) $(INC_DIRS) $(SYMBOLS) $(SRC_NAMESPACES_FS_UNSHARE) -o $(TARGET_NAMESPACES_FS_UNSHARE) $(C_COMPILER) $(CFLAGS) $(INC_DIRS) $(SYMBOLS) $(SRC_NAMESPACES_FS_CLONE) -o $(TARGET_NAMESPACES_FS_CLONE) + $(C_COMPILER) $(CFLAGS) $(INC_DIRS) $(SYMBOLS) $(SRC_NAMESPACES_FILES_CLONE) -o $(TARGET_NAMESPACES_FILES_CLONE) @echo @echo Finished preparing tests, running now. @@ -26,6 +31,7 @@ default: $(SRC_NAMESPACES_FS_UNSHARE) $(SRC_NAMESPACES_FS_CLONE) - ./$(TARGET_NAMESPACES_FS_UNSHARE) - ./$(TARGET_NAMESPACES_FS_CLONE) + - ./$(TARGET_NAMESPACES_FILES_CLONE) test_runners/namespaces_fs_TestUnshare_Runner.c: namespaces/fs/TestUnshare.c ruby $(UNITY_ROOT)/auto/generate_test_runner.rb namespaces/fs/TestUnshare.c test_runners/namespaces_fs_TestUnshare_Runner.c @@ -33,6 +39,9 @@ test_runners/namespaces_fs_TestUnshare_Runner.c: namespaces/fs/TestUnshare.c test_runners/namespaces_fs_TestClone_Runner.c: namespaces/fs/TestClone.c ruby $(UNITY_ROOT)/auto/generate_test_runner.rb namespaces/fs/TestClone.c test_runners/namespaces_fs_TestClone_Runner.c +test_runners/namespaces_files_TestClone_Runner.c: namespaces/files/TestClone.c + ruby $(UNITY_ROOT)/auto/generate_test_runner.rb namespaces/files/TestClone.c test_runners/namespaces_files_TestClone_Runner.c + clean: - $(CLEANUP) $(TARGET_NAMESPACES_FS_UNSHARE) $(TARGET_NAMESPACES_FS_CLONE) + $(CLEANUP) $(TARGET_NAMESPACES_FS_UNSHARE) $(TARGET_NAMESPACES_FS_CLONE) $(TARGET_NAMESPACES_FILES_CLONE) mkdir -p test_runners/ target/ diff --git a/assertions/namespaces/files/TestClone.c b/assertions/namespaces/files/TestClone.c new file mode 100644 index 0000000..1d346c8 --- /dev/null +++ b/assertions/namespaces/files/TestClone.c @@ -0,0 +1,199 @@ +#define _GNU_SOURCE + +#include "unity.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define STACK_SIZE (1024 * 1024) + +static char *TMP_DIR = NULL; + +void removeDirectory(char *dir) { + char cmd[256]; + sprintf(cmd, "rm -r %s", dir); + TEST_ASSERT_EQUAL(0, system(cmd)); +} + +void setUp(void) { + const char tmp_dir[] = "/tmp/tmpdir-XXXXXX"; + + TMP_DIR = malloc(sizeof(tmp_dir)); + strcpy(TMP_DIR, tmp_dir); + + TEST_ASSERT_NOT_EQUAL_MESSAGE(NULL, mkdtemp(TMP_DIR), "tmpdir failed"); +} + +void tearDown(void) { + removeDirectory(TMP_DIR); + free(TMP_DIR); + TMP_DIR = NULL; +} + +long clone3(struct clone_args *cl_args) { + return syscall(SYS_clone3, cl_args, sizeof(struct clone_args)); +} + +void test_cloneNoFiles_writeToExistingFd_succeeds(void) { + // PREPARE + + // ACT + pid_t forkedChildPid; + + if ((forkedChildPid = fork()) == 0) { + // child process - act but do not assert + // all assertions will be on the return code + + // prepare fd + int dirfd = open(TMP_DIR, O_DIRECTORY); + if (dirfd < 0) { + exit(1); // open dir failed + } + int filefd = openat(dirfd, "write", O_WRONLY | O_CREAT, 0700); + if (filefd < 0) { + exit(1); // open file failed + } + if (close(dirfd) != 0) { + exit(7); + } + + // clone + int clonedChildPidFd; + + struct clone_args cl_args = { + .flags = CLONE_PIDFD, + .pidfd = (uint64_t)(&clonedChildPidFd), + .child_tid = 0, + .parent_tid = 0, + .exit_signal = SIGCHLD, + .stack = 0, + .stack_size = 0, + .tls = 0, + .set_tid = 0, + .set_tid_size = 0, + .cgroup = 0, + }; + + long cloneResult = clone3(&cl_args); + if (cloneResult == 0) { + char buf[] = "hello world\n"; + if (write(filefd, buf, 13) == -1) { + exit(9); + } + + exit(0); + } else if (cloneResult == -1) { + exit(2); // clone failed + } + + siginfo_t status; + if (waitid(P_PIDFD, clonedChildPidFd, &status, WEXITED) == -1) { + exit(3); // wait failed + } + + if (status.si_status != 0) { + exit(status.si_status); // return status + } + + exit(0); + } + + // ASSERT + TEST_ASSERT_GREATER_THAN_MESSAGE(0, forkedChildPid, "fork failed"); + + int status = 0; + TEST_ASSERT_EQUAL_MESSAGE(forkedChildPid, waitpid(forkedChildPid, &status, 0), + "wait failed"); + TEST_ASSERT_EQUAL_MESSAGE(0, WEXITSTATUS(status), "return status non-zero"); +} + +void test_cloneFiles_writeToExistingFd_succeeds(void) { + // PREPARE + + // ACT + pid_t forkedChildPid; + + if ((forkedChildPid = fork()) == 0) { + // child process - act but do not assert + // all assertions will be on the return code + + // prepare fd + int dirfd = open(TMP_DIR, O_DIRECTORY); + if (dirfd < 0) { + exit(1); // open dir failed + } + int filefd = openat(dirfd, "write", O_WRONLY | O_CREAT, 0700); + if (filefd < 0) { + exit(1); // open file failed + } + if (close(dirfd) != 0) { + exit(7); + } + + // clone + int clonedChildPidFd; + + struct clone_args cl_args = { + .flags = CLONE_PIDFD | CLONE_FILES, + .pidfd = (uint64_t)(&clonedChildPidFd), + .child_tid = 0, + .parent_tid = 0, + .exit_signal = SIGCHLD, + .stack = 0, + .stack_size = 0, + .tls = 0, + .set_tid = 0, + .set_tid_size = 0, + .cgroup = 0, + }; + + long cloneResult = clone3(&cl_args); + if (cloneResult == 0) { + char buf[] = "hello world\n"; + if (write(filefd, buf, 13) == -1) { + exit(9); + } + + exit(0); + } else if (cloneResult == -1) { + exit(2); // clone failed + } + + siginfo_t status; + if (waitid(P_PIDFD, clonedChildPidFd, &status, WEXITED) == -1) { + exit(3); // wait failed + } + + if (status.si_status != 0) { + exit(status.si_status); // return status + } + + exit(0); + } + + // ASSERT + TEST_ASSERT_GREATER_THAN_MESSAGE(0, forkedChildPid, "fork failed"); + + int status = 0; + TEST_ASSERT_EQUAL_MESSAGE(forkedChildPid, waitpid(forkedChildPid, &status, 0), + "wait failed"); + TEST_ASSERT_EQUAL_MESSAGE(0, WEXITSTATUS(status), "return status non-zero"); +} + +void test_cloneNoFiles_writeToNewFd_fails(void) { TEST_IGNORE_MESSAGE("TODO"); } + +void test_cloneFiles_writeToNewFd_succeeds(void) { + TEST_IGNORE_MESSAGE("TODO"); +}