use crate::sandbox::Sandbox;
use anyhow::{Context, bail};
use std::fs;
use std::os::unix::process::CommandExt;
use std::path::Path;
use std::process::{Command, ExitStatus};
impl Sandbox {
pub fn mount_bindfs(
&self,
src: &Path,
dest: &Path,
opts: &[&str],
) -> anyhow::Result<Option<ExitStatus>> {
fs::create_dir_all(dest).with_context(|| format!("Failed to create {}", dest.display()))?;
let cmd = "/sbin/mount_null";
Ok(Some(
Command::new(cmd)
.args(opts)
.arg(src)
.arg(dest)
.process_group(0)
.status()
.context(format!("Unable to execute {}", cmd))?,
))
}
pub fn mount_devfs(
&self,
_src: &Path,
_dest: &Path,
_opts: &[&str],
) -> anyhow::Result<Option<ExitStatus>> {
bail!("NetBSD does not support 'dev' mounts. Use a 'cmd' action with MAKEDEV instead.")
}
pub fn mount_fdfs(
&self,
_src: &Path,
dest: &Path,
opts: &[&str],
) -> anyhow::Result<Option<ExitStatus>> {
fs::create_dir_all(dest).with_context(|| format!("Failed to create {}", dest.display()))?;
let cmd = "/sbin/mount_fdesc";
Ok(Some(
Command::new(cmd)
.args(opts)
.arg("fdesc")
.arg(dest)
.process_group(0)
.status()
.context(format!("Unable to execute {}", cmd))?,
))
}
pub fn mount_nfs(
&self,
src: &Path,
dest: &Path,
opts: &[&str],
) -> anyhow::Result<Option<ExitStatus>> {
fs::create_dir_all(dest).with_context(|| format!("Failed to create {}", dest.display()))?;
let cmd = "/sbin/mount_nfs";
Ok(Some(
Command::new(cmd)
.args(opts)
.arg(src)
.arg(dest)
.process_group(0)
.status()
.context(format!("Unable to execute {}", cmd))?,
))
}
pub fn mount_procfs(
&self,
_src: &Path,
dest: &Path,
opts: &[&str],
) -> anyhow::Result<Option<ExitStatus>> {
fs::create_dir_all(dest).with_context(|| format!("Failed to create {}", dest.display()))?;
let cmd = "/sbin/mount_procfs";
Ok(Some(
Command::new(cmd)
.args(opts)
.arg("/proc")
.arg(dest)
.process_group(0)
.status()
.context(format!("Unable to execute {}", cmd))?,
))
}
pub fn mount_tmpfs(
&self,
_src: &Path,
dest: &Path,
opts: &[&str],
) -> anyhow::Result<Option<ExitStatus>> {
fs::create_dir_all(dest).with_context(|| format!("Failed to create {}", dest.display()))?;
let cmd = "/sbin/mount_tmpfs";
Ok(Some(
Command::new(cmd)
.args(opts)
.arg("tmpfs")
.arg(dest)
.process_group(0)
.status()
.context(format!("Unable to execute {}", cmd))?,
))
}
fn unmount_common(&self, dest: &Path) -> anyhow::Result<Option<ExitStatus>> {
let cmd = "/sbin/umount";
Ok(Some(
Command::new(cmd)
.arg(dest)
.process_group(0)
.status()
.context(format!("Unable to execute {}", cmd))?,
))
}
pub fn unmount_bindfs(&self, dest: &Path) -> anyhow::Result<Option<ExitStatus>> {
self.unmount_common(dest)
}
pub fn unmount_devfs(&self, _dest: &Path) -> anyhow::Result<Option<ExitStatus>> {
bail!("NetBSD does not support 'dev' mounts. Use a 'cmd' action with MAKEDEV instead.")
}
pub fn unmount_fdfs(&self, dest: &Path) -> anyhow::Result<Option<ExitStatus>> {
self.unmount_common(dest)
}
pub fn unmount_nfs(&self, dest: &Path) -> anyhow::Result<Option<ExitStatus>> {
self.unmount_common(dest)
}
pub fn unmount_procfs(&self, dest: &Path) -> anyhow::Result<Option<ExitStatus>> {
self.unmount_common(dest)
}
pub fn unmount_tmpfs(&self, dest: &Path) -> anyhow::Result<Option<ExitStatus>> {
self.unmount_common(dest)
}
pub(super) fn find_pids(&self, sandbox: &Path) -> Vec<String> {
let output = Command::new("fstat").arg(sandbox).process_group(0).output();
let Ok(out) = output else { return vec![] };
String::from_utf8_lossy(&out.stdout)
.lines()
.skip(1)
.filter_map(|line| line.split_whitespace().nth(2))
.map(|s| s.to_string())
.collect()
}
}