extern crate libc;
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate thiserror;
mod builder;
mod flags;
mod fstype;
mod mount;
mod supported;
mod umount;
pub use self::{builder::*, flags::*, fstype::*, mount::*, supported::*, umount::*};
use libc::swapoff as c_swapoff;
use std::{
ffi::CString,
io::{self, Error, ErrorKind},
os::unix::ffi::OsStrExt,
path::Path,
};
#[derive(Debug, Error)]
pub enum ScopedMountError {
#[error("cannot get list of supported file systems")]
Supported(#[source] io::Error),
#[error("could not mount partition")]
Mount(#[source] io::Error),
}
pub fn scoped_mount<T, S: FnOnce() -> T>(
source: &Path,
mount_at: &Path,
scope: S,
) -> Result<T, ScopedMountError> {
let supported = SupportedFilesystems::new().map_err(ScopedMountError::Supported)?;
Mount::builder()
.fstype(&supported)
.mount(source, mount_at)
.map_err(ScopedMountError::Mount)?;
let result = scope();
if let Err(why) = unmount(mount_at, UnmountFlags::empty()) {
tracing::warn!("{}: failed to unmount: {}", mount_at.display(), why);
}
Ok(result)
}
pub fn swapoff<P: AsRef<Path>>(dest: P) -> io::Result<()> {
let Ok(swap) = CString::new(dest.as_ref().as_os_str().as_bytes().to_owned()) else {
return Err(Error::new(
ErrorKind::Other,
format!(
"swap path is not a valid c string: '{}'",
dest.as_ref().display()
)
))
};
match unsafe { c_swapoff(swap.as_ptr()) } {
0 => Ok(()),
_err => Err(Error::new(
ErrorKind::Other,
format!(
"failed to swapoff {}: {}",
dest.as_ref().display(),
Error::last_os_error()
),
)),
}
}
#[inline]
fn to_cstring(data: &[u8]) -> io::Result<CString> {
CString::new(data).map_err(|why| {
io::Error::new(
io::ErrorKind::InvalidData,
format!("failed to create `CString`: {}", why),
)
})
}