Skip to main content
Glama
disk.rs3.73 kB
use std::{ ffi::OsString, fs, fs::remove_dir_all, path::{ Path, PathBuf, }, result, }; use devicemapper::{ DM, DevId, DmName, DmOptions, }; use krataloopdev::LoopDevice; use nix::{ errno::Errno, mount::umount, }; use tracing::trace; use crate::errors::FirecrackerJailError; type Result<T> = result::Result<T, FirecrackerJailError>; const JAIL_PATH_PREFIX: &str = "/srv/jailer/firecracker/"; const ROOTFS: &str = "rootfs.ext4"; const OVERLAY_PREFIX: &str = "rootfs-overlay-"; #[derive(Debug)] pub struct FirecrackerDisk {} impl FirecrackerDisk { pub fn clean(id: u32) -> Result<()> { Self::unmount(id)?; Self::remove_overlay(id)?; Self::remove_loop(id)?; Self::remove_jail(id)?; Ok(()) } fn unmount(id: u32) -> Result<()> { let device = Self::jail_dir_from_id(id).join(ROOTFS); if device.exists() { trace!("Unmounting device {}", device.display()); match umount(&device) { Ok(_) => Ok(()), // it is more expensive to find out if it is not mounted than it is to // just try and swallow the failure Err(Errno::EINVAL) => { trace!( "Device not mounted, it has likely already been unmounted: {}", device.display() ); Ok(()) } Err(err) => Err(err), } .map_err(|err| FirecrackerJailError::Mount(err, device))? } Ok(()) } fn remove_overlay(id: u32) -> Result<()> { let overlay = Self::overlay_from_id(id); let dm = DM::new()?; let device = DmName::new(&overlay)?; let dev_id = &DevId::Name(device); if dm.device_info(dev_id).is_ok() { dm.device_remove(dev_id, DmOptions::private())?; } Ok(()) } fn remove_loop(id: u32) -> Result<()> { let device = Self::jail_dir_from_id(id).join(Self::overlay_from_id(id)); if let Some(loopdev) = Self::find_loop_device_by_backing_file(&device)? { trace!("Detaching from loop device {}", device.display()); let device = LoopDevice::open(loopdev)?; device.detach()?; } Ok(()) } fn remove_jail(id: u32) -> Result<()> { let jail = &Self::jail_dir_from_id(id); if jail.exists() { trace!("Removing {}", jail.display()); remove_dir_all(jail)?; } Ok(()) } pub fn jail_dir_from_id(id: u32) -> PathBuf { let path = PathBuf::from(JAIL_PATH_PREFIX); path.join(id.to_string()).join("root") } fn overlay_from_id(id: u32) -> String { format!("{OVERLAY_PREFIX}{id}") } fn find_loop_device_by_backing_file(backing_file: &Path) -> Result<Option<OsString>> { let sys_block_path = PathBuf::from("/sys/block"); for entry in fs::read_dir(sys_block_path)? { let entry = entry?; let path = entry.path(); if let Some(loop_name) = path .file_name() .and_then(|name| name.to_str()) .filter(|&name| name.starts_with("loop")) { let backing_file_path = path.join("loop").join("backing_file"); if let Ok(contents) = fs::read_to_string(&backing_file_path) { if contents.trim() == backing_file.to_string_lossy() { return Ok(Some(OsString::from(format!("/dev/{loop_name}")))); } } } } Ok(None) } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server