catj 0.2.3

A light process isolation sandbox used for competitive programming contest
Documentation
use crate::syscall::RestrictedSyscall;
use crate::utils::mount::MountPoint;
use crate::utils::{MemoryLimitType, TimeLimitType};
use std::path::PathBuf;

#[derive(Debug, Clone)]
pub(crate) struct LanguagePreset {
  pub(crate) compile: CompileOption,
  pub(crate) execute: ExecuteOption,
}

#[derive(Debug, Clone)]
pub(crate) struct CompileOption {
  pub(crate) extension: String,
  pub(crate) commands: Vec<ExecuteCommand>,
}

#[derive(Debug, Clone)]
pub(crate) struct ExecuteOption {
  pub(crate) commands: Vec<ExecuteCommand>,
}

#[derive(Debug, Clone)]
pub(crate) enum UserType {
  Nobody,
  Current,
  Root,
}

#[derive(Debug, Clone)]
pub struct ExecuteCommand {
  pub(crate) program: String,
  pub(crate) arguments: Vec<String>,
  pub(crate) time_limit: TimeLimitType,
  pub(crate) memory_limit: MemoryLimitType,
  pub(crate) user: UserType,
  pub(crate) process: u64,
  pub(crate) ptrace: Vec<RestrictedSyscall>,
  pub(crate) chroot: bool,
  pub(crate) mounts: Vec<MountPoint>,
  pub(crate) env: Vec<(String, String)>,
}

impl CompileOption {
  pub fn new<ES: Into<String>>(extension: ES) -> Self {
    CompileOption {
      extension: extension.into(),
      commands: vec![],
    }
  }

  pub fn command(mut self, command: ExecuteCommand) -> Self {
    self.commands.push(command);
    self
  }
}

impl ExecuteOption {
  pub fn new() -> Self {
    ExecuteOption { commands: vec![] }
  }

  pub fn command(mut self, command: ExecuteCommand) -> Self {
    self.commands.push(command);
    self
  }
}

impl ExecuteCommand {
  pub(crate) fn new<PS: Into<String>, AS: Into<String>>(program: PS, arguments: Vec<AS>) -> Self {
    ExecuteCommand {
      program: program.into(),
      arguments: arguments.into_iter().map(|a| a.into()).collect(),
      time_limit: 1000,
      memory_limit: 262144,
      user: UserType::Nobody,
      process: 1,
      ptrace: vec![RestrictedSyscall::Net, RestrictedSyscall::Process],
      chroot: true,
      mounts: vec![],
      env: vec![],
    }
  }

  fn apply(text: &str, source: &str, executable: &str) -> String {
    text
      .replace("${source}", source)
      .replace("${executable}", executable)
  }

  pub(crate) fn apply_program(&self, source: &str, executable: &str) -> String {
    Self::apply(self.program.as_str(), source, executable)
  }

  pub(crate) fn apply_arguments(&self, source: &str, executable: &str) -> Vec<String> {
    self
      .arguments
      .iter()
      .map(|a| Self::apply(a, source, executable))
      .collect()
  }

  pub(crate) fn default_time_limit(mut self, value: TimeLimitType) -> Self {
    self.time_limit = value;
    self
  }

  pub(crate) fn default_memory_limit(mut self, value: MemoryLimitType) -> Self {
    self.memory_limit = value;
    self
  }

  pub(crate) fn default_user(mut self, user_type: UserType) -> Self {
    self.user = user_type;
    self
  }

  pub(crate) fn default_process(mut self, value: u64) -> Self {
    self.process = value;
    self
  }

  pub(crate) fn default_ptrace(mut self, features: Vec<RestrictedSyscall>) -> Self {
    self.ptrace = features;
    self
  }

  pub(crate) fn default_chroot(mut self, flag: bool) -> Self {
    self.chroot = flag;
    self
  }

  pub(crate) fn append_read_mount(
    mut self,
    src: impl Into<PathBuf>,
    dst: impl Into<PathBuf>,
  ) -> Self {
    let point = MountPoint::read(src.into(), dst.into());
    self.mounts.push(point);
    self
  }

  pub(crate) fn append_write_mount(mut self) -> Self {
    self
  }

  pub(crate) fn append_env(mut self, key: String, value: String) -> Self {
    self.env.push((key, value));
    self
  }
}