use std::ffi::{OsStr, OsString};
use std::fmt::{self, Display, Formatter};
use std::path::{Path, PathBuf};
use std::time::Duration;
use serde::{Deserialize, Serialize};
#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
pub enum ShareNet {
Share,
#[default]
Unshare,
}
#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
pub enum SwapRedirects {
Yes,
#[default]
No,
}
#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
pub enum ClearUsage {
#[default]
Yes,
No,
}
#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
pub enum Interactive {
Yes,
#[default]
No,
}
#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
pub enum Aslr {
#[default]
Randomize,
NoRandomize,
}
#[derive(Debug, Eq, PartialEq, Copy, Clone, PartialOrd, Ord, Default, Serialize, Deserialize)]
pub struct SpaceUsage(u64);
impl SpaceUsage {
pub fn from_bytes(bytes: u64) -> Self {
Self(bytes)
}
pub fn from_kilobytes(kilobytes: u64) -> Self {
Self::from_bytes(kilobytes * 1_000)
}
pub fn from_megabytes(megabytes: u64) -> Self {
Self::from_kilobytes(megabytes * 1_000)
}
pub fn from_gigabytes(gigabytes: u64) -> Self {
Self::from_megabytes(gigabytes * 1_000)
}
pub fn from_kibibytes(kibibytes: u64) -> Self {
Self::from_bytes(kibibytes * 1_024)
}
pub fn from_mebibytes(mebibytes: u64) -> Self {
Self::from_kibibytes(mebibytes * 1_024)
}
pub fn from_gibibytes(gibibytes: u64) -> Self {
Self::from_mebibytes(gibibytes * 1_024)
}
pub fn as_bytes(self) -> u64 {
self.0
}
pub fn as_kilobytes(self) -> u64 {
self.0 / 1_000
}
}
impl Display for SpaceUsage {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
if self.0 % (1 << 30) == 0 {
write!(fmt, "{} gibibytes", self.0 >> 30)
} else if self.0 % (1 << 20) == 0 {
write!(fmt, "{} mebibytes", self.0 >> 20)
} else if self.0 % (1 << 10) == 0 {
write!(fmt, "{} kibibytes", self.0 >> 10)
} else if self.0 % 1_000_000_000 == 0 {
write!(fmt, "{} gigabytes", self.0 / 1_000_000_000)
} else if self.0 % 1_000_000 == 0 {
write!(fmt, "{} megabytes", self.0 / 1_000_000)
} else if self.0 % 1_000 == 0 {
write!(fmt, "{} kilobytes", self.0 / 1_000)
} else {
write!(fmt, "{} bytes", self.0)
}
}
}
#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)]
pub struct Limits {
pub wall_time: Option<Duration>,
pub user_time: Option<Duration>,
pub memory: Option<SpaceUsage>,
pub stack: Option<SpaceUsage>,
pub pids: Option<usize>,
}
impl Limits {
pub fn wall_time(&self) -> Option<Duration> {
self.wall_time
}
pub fn user_time(&self) -> Option<Duration> {
self.user_time
}
pub fn memory(&self) -> Option<SpaceUsage> {
self.memory
}
pub fn stack(&self) -> Option<SpaceUsage> {
self.stack
}
pub fn pids(&self) -> Option<usize> {
self.pids
}
}
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub struct MountOptions {
read_only: bool,
dev: bool,
exec: bool,
}
impl MountOptions {
pub fn read_only(self) -> bool {
self.read_only
}
pub fn dev(self) -> bool {
self.dev
}
pub fn exec(self) -> bool {
self.exec
}
pub fn set_read_only(&mut self, value: bool) {
self.read_only = value;
}
pub fn set_dev(&mut self, value: bool) {
self.dev = value;
}
pub fn set_exec(&mut self, value: bool) {
self.exec = value;
}
}
impl Default for MountOptions {
fn default() -> Self {
Self {
read_only: true,
dev: false,
exec: false,
}
}
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Mount {
source: PathBuf,
destination: PathBuf,
mount_options: MountOptions,
}
impl Mount {
pub fn new(source: PathBuf, destination: PathBuf, mount_options: MountOptions) -> Self {
Self {
source,
destination,
mount_options,
}
}
pub fn source(&self) -> &Path {
&self.source
}
pub fn destination(&self) -> &Path {
&self.destination
}
pub fn mount_options(&self) -> MountOptions {
self.mount_options
}
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum Environment {
Forward,
EnvList(Vec<(String, String)>),
}
impl Default for Environment {
fn default() -> Self {
Self::EnvList(Vec::new())
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct Config {
pub command: PathBuf,
pub args: Vec<OsString>,
pub new_root: Option<PathBuf>,
pub share_net: ShareNet,
pub redirect_stdin: Option<PathBuf>,
pub redirect_stdout: Option<PathBuf>,
pub redirect_stderr: Option<PathBuf>,
pub limits: Limits,
pub instance_name: OsString,
pub hierarchy_path: Option<PathBuf>,
pub mounts: Vec<Mount>,
pub swap_redirects: SwapRedirects,
pub clear_usage: ClearUsage,
pub interactive: Interactive,
pub aslr: Aslr,
pub privileged: bool,
pub environment: Environment,
}
impl Config {
pub fn command(&self) -> &Path {
&self.command
}
pub fn args(&self) -> Vec<&OsStr> {
self.args.iter().map(OsString::as_os_str).collect()
}
pub fn new_root(&self) -> Option<&Path> {
self.new_root.as_deref()
}
pub fn share_net(&self) -> ShareNet {
self.share_net
}
pub fn redirect_stdin(&self) -> Option<&Path> {
self.redirect_stdin.as_deref()
}
pub fn redirect_stdout(&self) -> Option<&Path> {
self.redirect_stdout.as_deref()
}
pub fn redirect_stderr(&self) -> Option<&Path> {
self.redirect_stderr.as_deref()
}
pub fn limits(&self) -> Limits {
self.limits
}
pub fn instance_name(&self) -> &OsStr {
&self.instance_name
}
pub fn hierarchy_path(&self) -> Option<&Path> {
self.hierarchy_path.as_deref()
}
pub fn mounts(&self) -> &[Mount] {
self.mounts.as_ref()
}
pub fn swap_redirects(&self) -> SwapRedirects {
self.swap_redirects
}
pub fn clear_usage(&self) -> ClearUsage {
self.clear_usage
}
pub fn interactive(&self) -> Interactive {
self.interactive
}
pub fn aslr(&self) -> Aslr {
self.aslr
}
pub fn environment(&self) -> &Environment {
&self.environment
}
}