container/src/container.c

96 lines
2.3 KiB
C
Raw Normal View History

2020-06-28 23:59:32 +00:00
#include "prototype.h"
#define __USE_GNU
#define _GNU_SOURCE
#include <sched.h>
#include <stdarg.h>
#include <signal.h>
#include <errno.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/syscall.h>
#include <sys/stat.h>
#define STACKSIZE (1024 * 1024)
static char child_stack[STACKSIZE];
/**
* child_exec is the func that will be executed as the result of clone
*/
int child_exec(void *stuff)
{
container_t *c = (container_t *)stuff;
struct clone_args *cloneArgs = &c->cloneArgs;
if (sethostname(cloneArgs->hostname, strlen(cloneArgs->hostname)) != 0)
{
container_error_handler(c, "fail to set new hostname");
}
if (execvp(cloneArgs->argv[0], cloneArgs->argv) != 0)
{
container_error_handler(c, "failed to execvp arguments\n");
}
// we should never reach here!
exit(EXIT_FAILURE);
}
/**
* 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_NEWNET | CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWPID | SIGCHLD;
c->cloneArgs = cloneArgs;
return c;
}
/**
* launch command into container
*/
pid_t run(container_t *c)
{
// the result of this call is that our child_exec will be run in another
// process returning it's pid
pid_t pid = clone(child_exec, child_stack + STACKSIZE, c->_cloneFlags, c);
if (pid < 0)
{
container_error_handler(c, "failed to run clone");
}
// lets wait on our child process here before we, the parent, exits
if (waitpid(pid, NULL, 0) == -1)
{
container_error_handler(c, "failed to wait pid %d", pid);
exit(EXIT_FAILURE);
}
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 container_error_handler(container_t *c, const char *error_msg, ...)
{
va_list arg;
va_start(arg, error_msg);
destroy_container(c);
error(error_msg, arg);
va_end(arg);
}
/**
* container destructor
*/
void destroy_container(container_t *c)
{
free(c);
}