alma/src/storage/mount_stack.rs
2020-05-31 08:38:20 +03:00

86 lines
2.1 KiB
Rust

use super::Filesystem;
use anyhow::anyhow;
use log::{debug, warn};
use nix::mount::{mount, umount, MsFlags};
use std::marker::PhantomData;
use std::path::PathBuf;
pub struct MountStack<'a> {
targets: Vec<PathBuf>,
filesystems: PhantomData<Filesystem<'a>>,
}
impl<'a> MountStack<'a> {
pub fn new() -> Self {
MountStack {
targets: Vec::new(),
filesystems: PhantomData,
}
}
pub fn mount(
&mut self,
filesystem: &'a Filesystem,
target: PathBuf,
options: Option<&str>,
) -> nix::Result<()> {
let source = filesystem.block().path();
debug!("Mounting {:?} to {:?}", filesystem, target);
mount(
Some(source),
&target,
Some(filesystem.fs_type().to_mount_type()),
MsFlags::MS_NOATIME,
options,
)?;
self.targets.push(target);
Ok(())
}
pub fn bind_mount(
&mut self,
source: PathBuf,
target: PathBuf,
options: Option<&str>,
) -> nix::Result<()> {
debug!("Mounting {:?} to {:?}", source, target);
mount::<_, _, str, _>(
Some(&source),
&target,
None,
MsFlags::MS_BIND | MsFlags::MS_NOATIME, // Read-only flag has no effect for bind mounts
options,
)?;
self.targets.push(target);
Ok(())
}
fn _umount(&mut self) -> anyhow::Result<()> {
let mut result = Ok(());
while let Some(target) = self.targets.pop() {
debug!("Unmounting {}", target.display());
if let Err(e) = umount(&target) {
warn!("Unable to umount {}: {}", target.display(), e);
result = Err(anyhow!(
"Failed unmounting filesystem: {}, {}",
target.display(),
e
));
};
}
result
}
pub fn umount(mut self) -> anyhow::Result<()> {
self._umount()
}
}
impl<'a> Drop for MountStack<'a> {
fn drop(&mut self) {
self._umount().ok();
}
}