/** * This file group all function which interact with system operation */ #ifndef _SYSTEM #define _SYSTEM #include "prototype.h" #include #include #include #include #include #include #include #include #include #define OLDROOT "/.old" /** * Wrapper for pivot root syscall */ int pivot_root(char *mount_dir) { char *inner_mount_dir = malloc( (sizeof(*(mount_dir)) * strlen(mount_dir) + 1) + strlen(OLDROOT)); strcpy(inner_mount_dir, mount_dir); strcat(inner_mount_dir, OLDROOT); if (mount("/", "/", "bind", MS_REC | MS_PRIVATE, NULL)) { error("error remount / with MS_PRIVATE"); } if (mount(mount_dir, mount_dir, "bind", MS_BIND | MS_REC, NULL) < 0) { error("error mount"); } if (mkdir(inner_mount_dir, 0755) != 0) { if (errno != EEXIST) { error("error mkdir"); } } int syscall_result = syscall(SYS_pivot_root, mount_dir, inner_mount_dir); // deal with old mount directory if (umount2(OLDROOT, MNT_DETACH) != 0) { error("umount old directory failed"); } if (rmdir(inner_mount_dir) != 0) { error("rm old directory failed"); } free(inner_mount_dir); return syscall_result; } /** * Umount pivot root folder */ int clean_pivot_root(char *a) { if (umount2(a, MNT_DETACH) != 0) { error("umount pivot_root directory failed"); return EXIT_FAILURE; } return EXIT_SUCCESS; } /** * Mount tmpfs into /dev and remount proc into /proc */ void remount() { // remount devtmpfs device to /dev with type devtmpfs if (mount(NULL, "/dev", "devtmpfs", MS_NOSUID | MS_STRICTATIME, NULL)) { error("failed mount tmpfs to /dev"); } // remount proc device to /proc with type proc if (mount(NULL, "/proc", "proc", MS_MGC_VAL, NULL)) { error("failed to re mount proc into /proc"); } // remount sys device to /sys with type sysfs if (mount(NULL, "/sys", "sysfs", MS_MGC_VAL, NULL)) { error("failed to re mount proc into /proc"); } } /** * Run external binary */ int run_subprocess(char *const *argv) { errno = execvp(argv[0], argv); return errno; } /** * Run external binary into new sub process */ int run_subprocess_async(int argc, char *const *argv) { pid_t pid; bool run_interactive = contain_interactive(argc, argv); // if container is running in interactive mode remove "-i" from argv if (run_interactive) { char **dst_argv = (char **)malloc(sizeof(char *) * argc); argc = filter_char_array(argc, (char **)argv, dst_argv, is_not_interactive); argv = dst_argv; } // pipe to permit parent => child comunication int pipe_parent_to_child_fd[2]; pipe(pipe_parent_to_child_fd); if ((pid = fork()) == -1) { error("fork() subprocess error"); } else if (pid == 0) { close(pipe_parent_to_child_fd[1]); // close writing end in the child printf("[CHILD] : running\n"); dup2(pipe_parent_to_child_fd[0], STDIN_FILENO); // send pipe to the stdin errno = execvp(argv[0], argv); return errno; } else { int child_status; close(pipe_parent_to_child_fd[0]); // close the read end of the pipe in the parent // if container is running in interactive mode if (run_interactive) { // read stdin write infinity write_infinite_fd(pipe_parent_to_child_fd[1]); } close(pipe_parent_to_child_fd[1]); // this descriptor is no longer needed // wait child if long task is in progress waitpid(pid, &child_status, 0); if (WIFEXITED(child_status)) { int es = WEXITSTATUS(child_status); printf("[PARENT] Exit status was %d\n", es); return es; } } // reach when wait child failed return EXIT_FAILURE; } /** * Return true if char* str is equal to "-i" */ bool is_interactive(char *str) { if (strcmp(str, "-i") == 0) { return true; } return false; } /** * Return true if char* str is not equal to "-i" * opposite of is_interactive */ bool is_not_interactive(char *str) { return !is_interactive(str); } /** * Return true if argv char* array contain "-i" */ bool contain_interactive(int argc, char *const *argv) { bool res = false; for (int i = 0; i < argc; i++) { if (is_interactive(argv[i])) { res = true; break; } } return res; } #endif