use c_str_macro::c_str;
use std::ffi::{CStr, CString};
#[derive(Debug, Clone)]
pub struct MountTable {
pub(crate) mounts: Vec<Mount>,
target_prefix: Option<CString>,
}
#[derive(Debug, Clone)]
pub struct Mount {
pub(crate) source: CString,
pub(crate) target: CString,
pub(crate) fstype: CString,
pub(crate) flags: u64,
pub(crate) data: Option<CString>,
pub(crate) create_mountpoint: Option<MountpointType>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MountpointType {
Dir,
File,
DetermineFromSource,
}
impl Mount {
pub fn create_mountpoint(&mut self, mountpoint_type: MountpointType) -> &mut Self {
self.create_mountpoint = Some(mountpoint_type);
self
}
}
impl Default for MountTable {
fn default() -> Self {
Self::new()
}
}
impl MountTable {
pub fn new() -> MountTable {
MountTable {
mounts: vec![],
target_prefix: None,
}
}
pub fn with_target_prefix(prefix: impl Into<CString>) -> MountTable {
MountTable {
mounts: vec![],
target_prefix: Some(prefix.into()),
}
}
pub fn target_prefix(&self) -> Option<&CStr> {
self.target_prefix.as_deref()
}
pub fn add_mount(
&mut self,
source: impl Into<CString>,
target: impl Into<CString>,
fstype: impl Into<CString>,
flags: u64,
data: Option<impl Into<CString>>,
) -> &mut Mount {
let prefixed_target: CString = match &self.target_prefix {
Some(prefix) => {
let mut new_target = prefix.clone().into_bytes();
new_target.push(b'/');
new_target.extend(target.into().as_bytes());
CString::new(new_target)
.expect("impossible for target_prefix or target to contain a NUL")
}
None => target.into(),
};
let mount = Mount {
source: source.into(),
target: prefixed_target,
fstype: fstype.into(),
flags,
data: data.map(|d| d.into()),
create_mountpoint: None,
};
self.mounts.push(mount);
self.mounts.last_mut().unwrap()
}
pub fn add_bind(
&mut self,
source: impl Into<CString>,
target: impl Into<CString>,
) -> &mut Mount {
self.add_mount(
source,
target,
CString::new("<bind>").unwrap(),
libc::MS_BIND | libc::MS_REC, None::<CString>,
)
.create_mountpoint(MountpointType::DetermineFromSource)
}
pub fn add_temp(&mut self, target: impl Into<CString>) {
self.add_mount(
CString::new("<dummy>").unwrap(),
target,
CString::new("tmpfs").unwrap(),
0,
None::<CString>,
)
.create_mountpoint(MountpointType::Dir);
}
pub fn add_proc(&mut self) {
self.add_mount(
CString::new("proc").unwrap(),
CString::new("proc").unwrap(),
CString::new("proc").unwrap(),
0,
None::<CString>,
)
.create_mountpoint(MountpointType::Dir);
}
pub fn add_sys(&mut self) {
self.add_bind(c_str!("/sys"), c_str!("/sys"))
.create_mountpoint(MountpointType::Dir);
}
pub fn add_sys_cgroup(&mut self) {
self.add_temp(c_str!("/sys/fs/cgroup"));
self.add_mount(
CString::new("cgroup").unwrap(),
CString::new("/sys/fs/cgroup").unwrap(),
CString::new("cgroup2").unwrap(), 0,
None::<CString>,
);
}
}