#[cfg(target_os = "linux")]
use which::which;
use std::path::{Path, PathBuf};
pub struct BwrapFinder {
system_path: Option<std::path::PathBuf>,
vendored_path: Option<std::path::PathBuf>,
}
impl BwrapFinder {
pub fn new() -> Self {
#[cfg(target_os = "linux")]
{
Self {
system_path: which("bwrap").ok(),
vendored_path: None,
}
}
#[cfg(not(target_os = "linux"))]
{
Self {
system_path: None,
vendored_path: None,
}
}
}
pub fn with_vendored(mut self, path: std::path::PathBuf) -> Self {
self.vendored_path = Some(path);
self
}
pub fn find(&self) -> Option<std::path::PathBuf> {
if let Some(ref path) = self.system_path {
return Some(path.clone());
}
self.vendored_path.clone()
}
pub fn is_available(&self) -> bool {
self.system_path.is_some() || self.vendored_path.is_some()
}
}
impl Default for BwrapFinder {
fn default() -> Self {
Self::new()
}
}
pub struct BwrapArgs {
args: Vec<String>,
}
impl BwrapArgs {
pub fn new() -> Self {
Self { args: Vec::new() }
}
pub fn cwd(mut self, path: &Path) -> Self {
self.args.push("--cwd".to_string());
self.args.push(path.to_string_lossy().to_string());
self
}
pub fn ro_bind(mut self, source: &Path, target: &Path) -> Self {
self.args.push("--ro-bind".to_string());
self.args.push(source.to_string_lossy().to_string());
self.args.push(target.to_string_lossy().to_string());
self
}
pub fn rw_bind(mut self, source: &Path, target: &Path) -> Self {
self.args.push("--rw".to_string());
self.args.push(source.to_string_lossy().to_string());
self.args.push(target.to_string_lossy().to_string());
self
}
pub fn tmp_dir(mut self, path: &str) -> Self {
self.args.push("--tmpfs".to_string());
self.args.push(path.to_string());
self
}
pub fn unshare_user(mut self) -> Self {
self.args.push("--unshare-user".to_string());
self
}
pub fn unshare_ipc(mut self) -> Self {
self.args.push("--unshare-ipc".to_string());
self
}
pub fn unshare_net(mut self) -> Self {
self.args.push("--unshare-net".to_string());
self
}
pub fn seccomp(mut self, fd: i32) -> Self {
self.args.push("--seccomp".to_string());
self.args.push(fd.to_string());
self
}
pub fn env(mut self, key: &str, value: &str) -> Self {
self.args.push("--env".to_string());
self.args.push(format!("{}={}", key, value));
self
}
pub fn separator(mut self) -> Self {
self.args.push("--".to_string());
self
}
pub fn command(mut self, argv: Vec<String>) -> Self {
self.args.extend(argv);
self
}
pub fn build(self) -> Vec<String> {
self.args
}
}
impl Default for BwrapArgs {
fn default() -> Self {
Self::new()
}
}
pub fn create_readonly_bwrap_command(argv: Vec<String>, cwd: &Path) -> Vec<String> {
BwrapArgs::new()
.cwd(cwd)
.ro_bind(Path::new("/"), Path::new("/"))
.separator()
.command(argv)
.build()
}
pub fn create_workspace_bwrap_command(
argv: Vec<String>,
cwd: &Path,
writable_roots: &[PathBuf],
) -> Vec<String> {
let mut args = BwrapArgs::new();
args = args.cwd(cwd);
for root in writable_roots {
args = args.rw_bind(root, root);
}
args = args.ro_bind(Path::new("/"), Path::new("/"));
args.separator().command(argv).build()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bwrap_finder() {
let finder = BwrapFinder::new();
let _ = finder.find();
}
#[test]
fn test_bwrap_args() {
let args = BwrapArgs::new()
.cwd(Path::new("/tmp"))
.ro_bind(Path::new("/usr"), Path::new("/usr"))
.separator()
.command(vec!["ls".to_string()])
.build();
assert!(args.contains(&"--cwd".to_string()));
assert!(args.contains(&"--ro-bind".to_string()));
}
}