212 lines
4.6 KiB
C
212 lines
4.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 <stdbool.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(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
|