/** * 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 #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(char *const *argv) { pid_t pid; // pipe to permit child => parent comunication int pipefd[2]; pipe(pipefd); if ((pid = fork()) == -1) { error("fork() subprocess error"); } else if (pid == 0) { close(pipefd[0]); // close reading end in the child printf("[CHILD] : running\n"); dup2(pipefd[1], 1); // send stdout to the pipe dup2(pipefd[1], 2); // send stderr to the pipe close(pipefd[1]); // this descriptor is no longer needed errno = execvp(argv[0], argv); return errno; } else { int child_status; close(pipefd[1]); // close the write end of the pipe in the parent waitpid(pid, &child_status, 0); if (WIFEXITED(child_status)) { char *stdout_buffer = read_infinite_fd(pipefd[0]); printf("[PARENT] child stdout : \n%s\n", stdout_buffer); free(stdout_buffer); close(pipefd[0]); // close the descriptor is no longer needed int es = WEXITSTATUS(child_status); printf("[PARENT] Exit status was %d\n", es); return es; } } // reach when wait child failed return EXIT_FAILURE; } #endif