Add ChrootedTask to run all tasks in a different (curently hardcoded) root
parent
29a12c5e5e
commit
8e2029cbb0
@ -0,0 +1,61 @@
|
||||
use std::{
|
||||
ffi::{c_int, CString},
|
||||
io,
|
||||
os::unix::prelude::OsStrExt,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use libc::CLONE_FS;
|
||||
use tokio::task::JoinHandle;
|
||||
|
||||
use crate::error::ChrootError;
|
||||
|
||||
pub struct ChrootedTask {
|
||||
root_path: PathBuf,
|
||||
}
|
||||
|
||||
impl ChrootedTask {
|
||||
/// Creates a new chrooted thread with the given path
|
||||
pub fn new<P: Into<PathBuf>>(root_path: P) -> Self {
|
||||
Self {
|
||||
root_path: root_path.into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs the given future in a new chroot
|
||||
pub fn run<F, T>(self, call: F) -> JoinHandle<Result<T, ChrootError>>
|
||||
where
|
||||
F: FnOnce() -> T + Send + 'static,
|
||||
T: Send + 'static,
|
||||
{
|
||||
let root_path = self.root_path;
|
||||
let handle = std::thread::spawn(move || {
|
||||
unsafe {
|
||||
init_chroot(&root_path)?;
|
||||
}
|
||||
Ok(call())
|
||||
});
|
||||
tokio::task::spawn_blocking(|| handle.join().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn init_chroot(path: &Path) -> Result<(), ChrootError> {
|
||||
handle_err_code(libc::unshare(CLONE_FS)).map_err(ChrootError::Unshare)?;
|
||||
let path_str = CString::new(path.as_os_str().as_bytes().to_vec()).unwrap();
|
||||
handle_err_code(libc::chroot(
|
||||
path_str.as_bytes_with_nul().as_ptr() as *const libc::c_char
|
||||
))
|
||||
.map_err(ChrootError::Chroot)?;
|
||||
std::env::set_current_dir(path).map_err(ChrootError::ChDir)?;
|
||||
std::env::set_var("PWD", "/");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_err_code(code: c_int) -> Result<(), io::Error> {
|
||||
if code != 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue