container/src/system.c

165 lines
3.6 KiB
C

/**
* This file group all function which interact with system operation
*/
#ifndef _SYSTEM
#define _SYSTEM
#include "prototype.h"
#include <errno.h>
#include <unistd.h>
#include <sys/mount.h>
#include <sys/syscall.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <string.h>
#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