#ifndef _CONTAINER #define _CONTAINER #include "prototype.h" #define __USE_GNU #define _GNU_SOURCE #include #include #include #include #include #include #define STACKSIZE (1024 * 1024) static char child_stack[STACKSIZE]; /** * Child_exec is the func that will be executed as the result of clone */ int container_create(void *stuff) { char rootfs_path[] = "./busybox"; container_t *c = (container_t *)stuff; struct clone_args *cloneArgs = &(c->cloneArgs); if (pivot_root(rootfs_path) != 0) { error_handler_container(c, "failed to pivot root"); } // mount dev, sys, proc into pivot root fs remount(); if (sethostname(cloneArgs->hostname, strlen(cloneArgs->hostname)) != 0) { error_handler_container(c, "fail to set new hostname"); } // run container command if (run_subprocess_async(cloneArgs->argc, cloneArgs->argv) != 0) { error_handler_container(c, "failed to execvp arguments"); } free(c); // free twice don't know why but maybe clone lost c reference c = NULL; // we end container return EXIT_SUCCESS; } /** * Container constructor initialize container_t object */ container_t *initialize_container(struct clone_args cloneArgs) { container_t *c = (container_t *)malloc(sizeof(container_t)); // in order new net ns, new mount ns, new hostname ns, new pid ns, child ns c->_cloneFlags = CLONE_NEWUSER | CLONE_NEWNET | CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWCGROUP; c->cloneArgs = cloneArgs; return c; } /** * Launch command into container */ pid_t run_container(container_t *c) { // the result of this call is that our child_exec will be run_container in another // process returning it's pid pid_t pid = clone(container_create, child_stack + STACKSIZE, c->_cloneFlags | SIGCHLD, c); if (pid < 0) { error_handler_container(c, "failed to run_container clone"); } // lets wait on our child process here before we, the parent, exit if (waitpid(pid, NULL, 0) == -1) { error_handler_container(c, "failed to wait pid %d", pid); } return pid; } /** * Handle error occured during container creation * this methode permit to call container_destroy * before printing error * take at last parameter variadic argument */ void error_handler_container(container_t *c, const char *error_msg, ...) { va_list arg; va_start(arg, error_msg); destroy_container(c); last_error(error_msg, arg); } /** * Container destructor */ void destroy_container(container_t *c) { free(c); } #endif