use std::ffi::CString;
use std::mem::MaybeUninit;
use std::path::{Path, PathBuf};
use crate::ffi_utils;
use crate::mount::ExitCode;
use crate::mount::ExitStatus;
use crate::mount::MountSource;
use crate::mount::UMountIter;
use crate::mount::UMountNamespace;
use crate::mount::UmntBuilder;
use crate::mount::UnmountBuilder;
use crate::mount::UnmountError;
#[derive(Debug)]
#[repr(transparent)]
pub struct Unmount {
pub(crate) inner: *mut libmount::libmnt_context,
}
impl Unmount {
#[doc(hidden)]
#[allow(dead_code)]
pub(crate) fn from_ptr(ptr: *mut libmount::libmnt_context) -> Unmount {
Self { inner: ptr }
}
#[doc(hidden)]
pub(crate) fn new() -> Result<Unmount, UnmountError> {
log::debug!("Unmount::new creating a new `Unmount` instance");
let mut inner = MaybeUninit::<*mut libmount::libmnt_context>::zeroed();
unsafe {
inner.write(libmount::mnt_new_context());
}
match unsafe { inner.assume_init() } {
inner if inner.is_null() => {
let err_msg = "failed to create a new `Unmount` instance".to_owned();
log::debug!(
"Unmount::new {}. libmount::mnt_new_contex returned a NULL pointer",
err_msg
);
Err(UnmountError::Creation(err_msg))
}
inner => {
log::debug!("Unmount::new created a new `Unmount` instance");
let mount = Self::from_ptr(inner);
Ok(mount)
}
}
}
#[doc(hidden)]
fn return_code_to_exit_status(&self, return_code: i32) -> Result<ExitStatus, UnmountError> {
log::debug!(
"Unmount::return_code_to_exit_status converting to exit status the return code: {:?}",
return_code
);
const BUFFER_LENGTH: usize = 4097; let mut buffer: Vec<libc::c_char> = vec![0; BUFFER_LENGTH];
let rc = unsafe {
libmount::mnt_context_get_excode(
self.inner,
return_code,
buffer.as_mut_ptr(),
BUFFER_LENGTH,
)
};
let exit_code = ExitCode::try_from(rc)?;
let error_message = ffi_utils::c_char_array_to_string(buffer.as_ptr());
let exit_status = ExitStatus::new(exit_code, error_message);
log::debug!(
"Unmount::return_code_to_exit_status converted return code: {:?} to exit status {:?}",
return_code,
exit_status
);
Ok(exit_status)
}
#[doc(hidden)]
fn enable_delete_loop_device(
mount: *mut libmount::libmnt_context,
enable: bool,
) -> Result<(), UnmountError> {
let op = if enable { 1 } else { 0 };
let op_str = if enable {
"enable".to_owned()
} else {
"disable".to_owned()
};
let result = unsafe { libmount::mnt_context_enable_loopdel(mount, op) };
match result {
0 => {
log::debug!(
"Unmount::enable_delete_loop_device {}d loop device deletion after unmount",
op_str
);
Ok(())
}
code => {
let err_msg = format!("failed to {} loop device deletion after unmount", op_str);
log::debug!("Unmount::enable_delete_loop_device {}. libmount::mnt_context_enable_loopdel returned error code: {:?}", err_msg, code);
Err(UnmountError::Config(err_msg))
}
}
}
#[doc(hidden)]
pub(crate) fn enable_detach_loop_device(&mut self) -> Result<(), UnmountError> {
log::debug!(
"Unmount::enable_detach_loop_device enabling loop device deletion after unmount"
);
Self::enable_delete_loop_device(self.inner, true)
}
#[doc(hidden)]
pub(crate) fn disable_detach_loop_device(&mut self) -> Result<(), UnmountError> {
log::debug!(
"Unmount::disable_detach_loop_device disabling loop device deletion after unmount"
);
Self::enable_delete_loop_device(self.inner, false)
}
#[doc(hidden)]
fn disable_canonicalize(
mount: *mut libmount::libmnt_context,
disable: bool,
) -> Result<(), UnmountError> {
let op = if disable { 1 } else { 0 };
let op_str = if disable {
"disable".to_owned()
} else {
"enable".to_owned()
};
let result = unsafe { libmount::mnt_context_disable_canonicalize(mount, op) };
match result {
0 => {
log::debug!(
"Unmount::disable_canonicalize {}d path canonicalization",
op_str
);
Ok(())
}
code => {
let err_msg = format!("failed to {} path canonicalization", op_str);
log::debug!("Unmount::disable_canonicalize {}. libmount::mnt_context_disable_canonicalize returned error code: {:?}", err_msg, code);
Err(UnmountError::Config(err_msg))
}
}
}
#[doc(hidden)]
pub(crate) fn disable_path_canonicalization(&mut self) -> Result<(), UnmountError> {
log::debug!("Unmount::disable_path_canonicalization disabling path canonicalization");
Self::disable_canonicalize(self.inner, true)
}
#[doc(hidden)]
pub(crate) fn enable_path_canonicalization(&mut self) -> Result<(), UnmountError> {
log::debug!("Unmount::enable_path_canonicalization enabling path canonicalization");
Self::disable_canonicalize(self.inner, false)
}
#[doc(hidden)]
fn disable_mnt_helpers(
mount: *mut libmount::libmnt_context,
disable: bool,
) -> Result<(), UnmountError> {
let op = if disable { 1 } else { 0 };
let op_str = if disable {
"disable".to_owned()
} else {
"enable".to_owned()
};
let result = unsafe { libmount::mnt_context_disable_helpers(mount, op) };
match result {
0 => {
log::debug!(
"Unmount::disable_mnt_helpers {}d mount/umount helpers",
op_str
);
Ok(())
}
code => {
let err_msg = format!("failed to {} mount/umount helpers", op_str);
log::debug!("Unmount::disable_mnt_helpers {}. libmount::mnt_context_disable_helpers returned error code: {:?}", err_msg, code);
Err(UnmountError::Config(err_msg))
}
}
}
#[doc(hidden)]
pub(crate) fn disable_helpers(&mut self) -> Result<(), UnmountError> {
log::debug!("Unmount::disable_helpers disabling mount/umount helpers");
Self::disable_mnt_helpers(self.inner, true)
}
#[doc(hidden)]
pub(crate) fn enable_helpers(&mut self) -> Result<(), UnmountError> {
log::debug!("Unmount::enable_helpers enabling mount/umount helpers");
Self::disable_mnt_helpers(self.inner, false)
}
#[doc(hidden)]
fn disable_swap_match(
mount: *mut libmount::libmnt_context,
disable: bool,
) -> Result<(), UnmountError> {
let op = if disable { 1 } else { 0 };
let op_str = if disable {
"disable".to_owned()
} else {
"enable".to_owned()
};
let result = unsafe { libmount::mnt_context_disable_swapmatch(mount, op) };
match result {
0 => {
log::debug!("Unmount::disable_swap_match {}d mount point lookup", op_str);
Ok(())
}
code => {
let err_msg = format!("failed to {} mount point lookup", op_str);
log::debug!("Unmount::disable_swap_match {}. libmount::mnt_context_disable_swapmatch returned error code: {:?}", err_msg, code);
Err(UnmountError::Config(err_msg))
}
}
}
#[doc(hidden)]
pub(crate) fn disable_mount_point_lookup(&mut self) -> Result<(), UnmountError> {
log::debug!("Unmount::disable_mount_point_lookup disabling mount point lookup");
Self::disable_swap_match(self.inner, true)
}
#[doc(hidden)]
pub(crate) fn enable_mount_point_lookup(&mut self) -> Result<(), UnmountError> {
log::debug!("Unmount::enable_mount_point_lookup enabling mount point lookup");
Self::disable_swap_match(self.inner, false)
}
#[doc(hidden)]
fn disable_mtab(
mount: *mut libmount::libmnt_context,
disable: bool,
) -> Result<(), UnmountError> {
let op = if disable { 1 } else { 0 };
let op_str = if disable {
"disable".to_owned()
} else {
"enable".to_owned()
};
let result = unsafe { libmount::mnt_context_disable_mtab(mount, op) };
match result {
0 => {
log::debug!(
"Unmount::disable_mtab {}d userspace mount table updates",
op_str
);
Ok(())
}
code => {
let err_msg = format!("failed to {} userspace mount table updates", op_str);
log::debug!("Unmount::disable_mtab {}. libmount::mnt_context_disable_mtab returned error code: {:?}", err_msg, code);
Err(UnmountError::Config(err_msg))
}
}
}
#[doc(hidden)]
pub(crate) fn do_not_update_utab(&mut self) -> Result<(), UnmountError> {
log::debug!("Unmount::do_not_update_utab disabling userspace mount table updates");
Self::disable_mtab(self.inner, true)
}
#[doc(hidden)]
pub(crate) fn update_utab(&mut self) -> Result<(), UnmountError> {
log::debug!("Unmount::update_utab enabling userspace mount table updates");
Self::disable_mtab(self.inner, false)
}
#[doc(hidden)]
fn enable_fake(mount: *mut libmount::libmnt_context, enable: bool) -> Result<(), UnmountError> {
let op = if enable { 1 } else { 0 };
let op_str = if enable {
"enable".to_owned()
} else {
"disable".to_owned()
};
let result = unsafe { libmount::mnt_context_enable_fake(mount, op) };
match result {
0 => {
log::debug!("Unmount::enable_fake {}d dry run", op_str);
Ok(())
}
code => {
let err_msg = format!("failed to {} dry run", op_str);
log::debug!("Unmount::enable_fake {}. libmount::mnt_context_enable_fake returned error code: {:?}", err_msg, code);
Err(UnmountError::Config(err_msg))
}
}
}
#[doc(hidden)]
pub(crate) fn enable_dry_run(&mut self) -> Result<(), UnmountError> {
log::debug!("Unmount::enable_dry_run enabling dry run");
Self::enable_fake(self.inner, true)
}
#[doc(hidden)]
pub(crate) fn disable_dry_run(&mut self) -> Result<(), UnmountError> {
log::debug!("Unmount::disable_dry_run disabling dry run");
Self::enable_fake(self.inner, false)
}
#[doc(hidden)]
fn enable_force_device_unmount(
mount: *mut libmount::libmnt_context,
enable: bool,
) -> Result<(), UnmountError> {
let op = if enable { 1 } else { 0 };
let op_str = if enable {
"enable".to_owned()
} else {
"disable".to_owned()
};
let result = unsafe { libmount::mnt_context_enable_force(mount, op) };
match result {
0 => {
log::debug!(
"Unmount::enable_force_device_unmount {}d force device unmount",
op_str
);
Ok(())
}
code => {
let err_msg = format!("failed to {} force device unmount", op_str);
log::debug!("Unmount::enable_force_device_unmount {}. libmount::mnt_context_enable_force returned error code: {:?}", err_msg, code);
Err(UnmountError::Config(err_msg))
}
}
}
#[doc(hidden)]
pub(crate) fn enable_force_unmount(&mut self) -> Result<(), UnmountError> {
log::debug!("Unmount::enable_force_unmount enabling force device unmount");
Self::enable_force_device_unmount(self.inner, true)
}
#[doc(hidden)]
pub(crate) fn disable_force_unmount(&mut self) -> Result<(), UnmountError> {
log::debug!("Unmount::disable_force_unmount disabling force device unmount");
Self::enable_force_device_unmount(self.inner, false)
}
#[doc(hidden)]
fn enable_lazy_device_unmount(
mount: *mut libmount::libmnt_context,
enable: bool,
) -> Result<(), UnmountError> {
let op = if enable { 1 } else { 0 };
let op_str = if enable {
"enable".to_owned()
} else {
"disable".to_owned()
};
let result = unsafe { libmount::mnt_context_enable_lazy(mount, op) };
match result {
0 => {
log::debug!(
"Unmount::enable_lazy_device_unmount {}d lazy device unmount",
op_str
);
Ok(())
}
code => {
let err_msg = format!("failed to {} lazy device unmount", op_str);
log::debug!("Unmount::enable_lazy_device_unmount {}. libmount::mnt_context_enable_lazy returned error code: {:?}", err_msg, code);
Err(UnmountError::Config(err_msg))
}
}
}
#[doc(hidden)]
pub(crate) fn enable_lazy_unmount(&mut self) -> Result<(), UnmountError> {
log::debug!("Unmount::enable_lazy_umount enabling lazy device unmount");
Self::enable_lazy_device_unmount(self.inner, true)
}
#[doc(hidden)]
pub(crate) fn disable_lazy_unmount(&mut self) -> Result<(), UnmountError> {
log::debug!("Unmount::disable_lazy_umount disabling lazy device unmount");
Self::enable_lazy_device_unmount(self.inner, false)
}
#[doc(hidden)]
fn enable_verbose(
mount: *mut libmount::libmnt_context,
enable: bool,
) -> Result<(), UnmountError> {
let op = if enable { 1 } else { 0 };
let op_str = if enable {
"enable".to_owned()
} else {
"disable".to_owned()
};
let result = unsafe { libmount::mnt_context_enable_verbose(mount, op) };
match result {
0 => {
log::debug!("Unmount::enable_verbose {}d verbose output", op_str);
Ok(())
}
code => {
let err_msg = format!("failed to {} verbose output", op_str);
log::debug!("Unmount::enable_verbose {}. libmount::mnt_context_enable_verbose returned error code: {:?}", err_msg, code);
Err(UnmountError::Config(err_msg))
}
}
}
#[doc(hidden)]
pub(crate) fn enable_verbose_output(&mut self) -> Result<(), UnmountError> {
log::debug!("Unmount::enable_verbose_output enabling verbose output");
Self::enable_verbose(self.inner, true)
}
#[doc(hidden)]
pub(crate) fn disable_verbose_output(&mut self) -> Result<(), UnmountError> {
log::debug!("Unmount::disable_verbose_output disabling verbose output");
Self::enable_verbose(self.inner, false)
}
#[doc(hidden)]
fn enable_read_only_unmount(
mount: *mut libmount::libmnt_context,
enable: bool,
) -> Result<(), UnmountError> {
let op = if enable { 1 } else { 0 };
let op_str = if enable {
"enable".to_owned()
} else {
"disable".to_owned()
};
let result = unsafe { libmount::mnt_context_enable_rdonly_umount(mount, op) };
match result {
0 => {
log::debug!(
"Unmount::enable_read_only_unmount {}d remount read-only after failed unmount",
op_str
);
Ok(())
}
code => {
let err_msg = format!(
"failed to {} remount read-only after failed unmount",
op_str
);
log::debug!("Unmount::enable_read_only_unmount {}. libmount::mnt_context_enable_rdonly_umount returned error code: {:?}", err_msg, code);
Err(UnmountError::Config(err_msg))
}
}
}
#[doc(hidden)]
pub(crate) fn enable_on_fail_remount_read_only(&mut self) -> Result<(), UnmountError> {
log::debug!(
"Unmount::enable_on_fail_remount_read_only enabling read only remount after failed unmount"
);
Self::enable_read_only_unmount(self.inner, true)
}
#[doc(hidden)]
pub(crate) fn disable_on_fail_remount_read_only(&mut self) -> Result<(), UnmountError> {
log::debug!(
"Unmount::disable_on_fail_remount_read_only disabling read only remount after failed unmount"
);
Self::enable_read_only_unmount(self.inner, false)
}
#[doc(hidden)]
pub(crate) fn set_file_systems_filter<T>(&mut self, fs_list: T) -> Result<(), UnmountError>
where
T: AsRef<str>,
{
let fs_list = fs_list.as_ref();
let fs_list_cstr = ffi_utils::as_ref_str_to_c_string(fs_list)?;
log::debug!(
"Unmount::set_file_systems_filter setting the list of file systems: {:?}",
fs_list
);
let result =
unsafe { libmount::mnt_context_set_fstype_pattern(self.inner, fs_list_cstr.as_ptr()) };
match result {
0 => {
log::debug!(
"Unmount::set_file_systems_filter set the list of file systems: {:?}",
fs_list
);
Ok(())
}
code => {
let err_msg = format!("failed to set file systems list: {:?}", fs_list);
log::debug!("Unmount::set_file_systems_filter {}. libmount::mnt_context_set_fstype_pattern returned error code: {:?}", err_msg, code);
Err(UnmountError::Config(err_msg))
}
}
}
#[doc(hidden)]
pub(crate) fn set_mount_options_filter<T>(
&mut self,
options_list: T,
) -> Result<(), UnmountError>
where
T: AsRef<str>,
{
let options_list = options_list.as_ref();
let options_list_cstr = ffi_utils::as_ref_str_to_c_string(options_list)?;
log::debug!(
"Unmount::set_mount_options_filter setting mount options filter: {:?}",
options_list
);
let result = unsafe {
libmount::mnt_context_set_options_pattern(self.inner, options_list_cstr.as_ptr())
};
match result {
0 => {
log::debug!(
"Unmount::set_mount_options_filter set mount options filter: {:?}",
options_list
);
Ok(())
}
code => {
let err_msg = format!("failed to set mount options filter: {:?}", options_list);
log::debug!("Unmount::set_mount_options_filter {}. libmount::mnt_context_set_options_pattern returned error code: {:?}", err_msg, code);
Err(UnmountError::Config(err_msg))
}
}
}
#[doc(hidden)]
fn set_source(
mount: *mut libmount::libmnt_context,
source: CString,
) -> Result<(), UnmountError> {
let result = unsafe { libmount::mnt_context_set_source(mount, source.as_ptr()) };
match result {
0 => {
log::debug!("Unmount::set_source mount source set");
Ok(())
}
code => {
let err_msg = format!("failed to set mount source: {:?}", source);
log::debug!("Unmount::set_source {}. libmount::mnt_context_set_source returned error code: {:?}", err_msg, code);
Err(UnmountError::Config(err_msg))
}
}
}
#[doc(hidden)]
pub(crate) fn set_mount_source(&mut self, source: MountSource) -> Result<(), UnmountError> {
let source = source.to_string();
let source_cstr = ffi_utils::as_ref_path_to_c_string(&source)?;
log::debug!(
"Unmount::set_mount_source setting mount source: {:?}",
source
);
Self::set_source(self.inner, source_cstr)
}
#[doc(hidden)]
pub(crate) fn set_mount_target<T>(&mut self, target: T) -> Result<(), UnmountError>
where
T: AsRef<Path>,
{
let target = target.as_ref();
let target_cstr = ffi_utils::as_ref_path_to_c_string(target)?;
log::debug!(
"Unmount::set_mount_target setting mount target to: {:?}",
target
);
let result = unsafe { libmount::mnt_context_set_target(self.inner, target_cstr.as_ptr()) };
match result {
0 => {
log::debug!(
"Unmount::set_mount_target set mount target to: {:?}",
target
);
Ok(())
}
code => {
let err_msg = format!("failed to set mount target to: {:?}", target);
log::debug!("Unmount::set_mount_target {}. libmount::mnt_context_set_target returned error code: {:?}", err_msg, code);
Err(UnmountError::Config(err_msg))
}
}
}
#[doc(hidden)]
pub(crate) fn set_mount_target_namespace<T>(&mut self, path: T) -> Result<(), UnmountError>
where
T: AsRef<Path>,
{
let path = path.as_ref();
let path_cstr = ffi_utils::as_ref_path_to_c_string(path)?;
log::debug!(
"Unmount::set_mount_target_namespace setting mount target namespace: {:?}",
path
);
let result = unsafe { libmount::mnt_context_set_target_ns(self.inner, path_cstr.as_ptr()) };
match result {
0 => {
log::debug!(
"Unmount::set_mount_target_namespace set mount target namespace: {:?}",
path
);
Ok(())
}
code if code == -libc::ENOSYS => {
let err_msg = "`libmount` was compiled without namespace support".to_owned();
log::debug!("Unmount::set_mount_target_namespace {}. libmount::mnt_context_set_target returned error code: {:?}", err_msg, code);
Err(UnmountError::NoNamespaceSupport(err_msg))
}
code => {
let err_msg = format!("failed to set mount target namespace: {:?}", path);
log::debug!("Unmount::set_mount_target_namespace {}. libmount::mnt_context_set_target_ns returned error code: {:?}", err_msg, code);
Err(UnmountError::Config(err_msg))
}
}
}
pub fn builder() -> UnmountBuilder {
log::debug!("Unmount::builder creating new `UnmountBuilder` instance");
UmntBuilder::builder()
}
pub fn unmount_device(&mut self) -> Result<ExitStatus, UnmountError> {
log::debug!("Unmount::unmount_device unmounting device");
let return_code = unsafe { libmount::mnt_context_umount(self.inner) };
self.return_code_to_exit_status(return_code)
}
pub fn prepare_unmount(&mut self) -> Result<(), UnmountError> {
log::debug!("Unmount::prepare_unmount preparing for unmount");
let result = unsafe { libmount::mnt_context_prepare_umount(self.inner) };
match result {
0 => {
log::debug!("Unmount::prepare_unmount preparation successful");
Ok(())
}
code => {
let err_msg = "failed to prepare for device unmount".to_owned();
log::debug!("Unmount::prepare_unmount {}. libmount::mnt_context_prepare_umount returned error code: {:?}", err_msg, code);
Err(UnmountError::Config(err_msg))
}
}
}
pub fn call_umount_syscall(&mut self) -> Result<ExitStatus, UnmountError> {
log::debug!("Unmount::call_umount_syscall unmounting device");
let return_code = unsafe { libmount::mnt_context_do_umount(self.inner) };
self.return_code_to_exit_status(return_code)
}
pub fn finalize_umount(&mut self) -> Result<(), UnmountError> {
log::debug!("Unmount::finalize_umount finalizing unmount");
let result = unsafe { libmount::mnt_context_finalize_umount(self.inner) };
match result {
0 => {
log::debug!("Unmount::finalize_umount finalized unmount");
Ok(())
}
code => {
let err_msg = "failed to finalize device unmount".to_owned();
log::debug!("Unmount::finalize_umount {}. libmount::mnt_context_finalize_umount returned error code: {:?}", err_msg, code);
Err(UnmountError::Config(err_msg))
}
}
}
pub fn set_syscall_exit_status(&mut self, exit_status: i32) -> Result<(), UnmountError> {
log::debug!(
"Unmount::set_syscall_exit_status setting mount/umount syscall exit status to {:?}",
exit_status
);
let result = unsafe { libmount::mnt_context_set_syscall_status(self.inner, exit_status) };
match result {
0 => {
log::debug!(
"Unmount::set_syscall_exit_status set mount/umount syscall exit status to {:?}",
exit_status
);
Ok(())
}
code => {
let err_msg = format!(
"ailed to set mount/umount syscall exit status to {:?}",
exit_status
);
log::debug!("Unmount::set_syscall_exit_status {}. libmount::mnt_context_set_syscall_status returned error code: {:?}", err_msg, code);
Err(UnmountError::Config(err_msg))
}
}
}
pub fn reset_syscall_exit_status(&mut self) -> Result<(), UnmountError> {
log::debug!("Unmount::reset_syscall_exit_status resetting syscall exit status");
let result = unsafe { libmount::mnt_context_reset_status(self.inner) };
match result {
0 => {
log::debug!("Unmount::reset_syscall_exit_status reset syscall exit status");
Ok(())
}
code => {
let err_msg = "failed to reset syscall exit status".to_owned();
log::debug!("Unmount::reset_syscall_exit_status {}. libmount::mnt_context_reset_status returned error code: {:?}", err_msg, code);
Err(UnmountError::Config(err_msg))
}
}
}
pub fn switch_to_namespace(
&mut self,
namespace: UMountNamespace,
) -> Option<UMountNamespace<'_>> {
log::debug!("Unmount::switch_to_namespace switching namespace");
let mut ptr = MaybeUninit::<*mut libmount::libmnt_ns>::zeroed();
unsafe {
ptr.write(libmount::mnt_context_switch_ns(self.inner, namespace.ptr));
}
match unsafe { ptr.assume_init() } {
ptr if ptr.is_null() => {
let err_msg = "found no prior namespace";
log::debug!("Unmount::switch_to_namespace {}. libmount::mnt_context_switch_ns returned a NULL pointer", err_msg);
None
}
ptr => {
log::debug!("Unmount::switch_to_namespace switched namespace");
let namespace = UMountNamespace::from_raw_parts(ptr, self);
Some(namespace)
}
}
}
pub fn switch_to_original_namespace(&mut self) -> Option<UMountNamespace<'_>> {
log::debug!("Unmount::switch_to_original_namespace switching to original namespace");
let mut ptr = MaybeUninit::<*mut libmount::libmnt_ns>::zeroed();
unsafe {
ptr.write(libmount::mnt_context_switch_origin_ns(self.inner));
}
match unsafe { ptr.assume_init() } {
ptr if ptr.is_null() => {
let err_msg = "found no prior namespace";
log::debug!("Unmount::switch_to_original_namespace {}. libmount::mnt_context_switch_origin_ns returned a NULL pointer", err_msg);
None
}
ptr => {
log::debug!("Unmount::switch_to_original_namespace switched to original namespace");
let namespace = UMountNamespace::from_raw_parts(ptr, self);
Some(namespace)
}
}
}
pub fn switch_to_target_namespace(&mut self) -> Option<UMountNamespace<'_>> {
log::debug!("Unmount::switch_to_target_namespace switching to target namespace");
let mut ptr = MaybeUninit::<*mut libmount::libmnt_ns>::zeroed();
unsafe {
ptr.write(libmount::mnt_context_switch_target_ns(self.inner));
}
match unsafe { ptr.assume_init() } {
ptr if ptr.is_null() => {
let err_msg = "found no prior namespace";
log::debug!("Unmount::switch_to_target_namespace {}. libmount::mnt_context_switch_target_ns returned a NULL pointer", err_msg);
None
}
ptr => {
log::debug!("Unmount::switch_to_target_namespace switched to target namespace");
let namespace = UMountNamespace::from_raw_parts(ptr, self);
Some(namespace)
}
}
}
pub fn source(&self) -> Option<String> {
log::debug!("Unmount::source getting identifier of device to mount");
let mut identifier = MaybeUninit::<*const libc::c_char>::zeroed();
unsafe {
identifier.write(libmount::mnt_context_get_source(self.inner));
}
match unsafe { identifier.assume_init() } {
ptr if ptr.is_null() => {
let err_msg = "failed to get identifier of device to mount";
log::debug!(
"Unmount::source {}. libmount::mnt_context_get_source returned a NULL pointer",
err_msg
);
None
}
ptr => {
log::debug!("Unmount::source got identifier of device to mount");
let source = ffi_utils::c_char_array_to_string(ptr);
Some(source)
}
}
}
pub fn target(&self) -> Option<PathBuf> {
log::debug!("Unmount::target getting mount point");
let mut mount_point = MaybeUninit::<*const libc::c_char>::zeroed();
unsafe {
mount_point.write(libmount::mnt_context_get_target(self.inner));
}
match unsafe { mount_point.assume_init() } {
ptr if ptr.is_null() => {
let err_msg = "failed to get mount point";
log::debug!(
"Unmount::target {}. libmount::mnt_context_get_target returned a NULL pointer",
err_msg
);
None
}
ptr => {
log::debug!("Unmount::target got mount point");
let target = ffi_utils::const_c_char_array_to_path_buf(ptr);
Some(target)
}
}
}
pub fn target_namespace(&self) -> Option<UMountNamespace<'_>> {
log::debug!("Unmount::target_namespace getting mount point's namespace");
let mut ptr = MaybeUninit::<*mut libmount::libmnt_ns>::zeroed();
unsafe {
ptr.write(libmount::mnt_context_get_target_ns(self.inner));
}
match unsafe { ptr.assume_init() } {
ptr if ptr.is_null() => {
let err_msg = "found no mount point namespace";
log::debug!("Unmount::target_namespace {}. libmount::mnt_context_get_target_ns returned a NULL pointer", err_msg);
None
}
ptr => {
log::debug!("Unmount::target_namespace got mount point's namespace");
let ns = UMountNamespace::from_raw_parts(ptr, self);
Some(ns)
}
}
}
pub fn umount_helper_exit_status(&self) -> i32 {
let status = unsafe { libmount::mnt_context_get_helper_status(self.inner) };
log::debug!("Unmount::umount_helper_exit_status value: {:?}", status);
status
}
pub fn umount_syscall_errno(&self) -> Option<i32> {
log::debug!("Unmount::umount_syscall_errno getting mount(2) syscall error number");
let result = unsafe { libmount::mnt_context_get_syscall_errno(self.inner) };
match result {
0 => {
let err_msg = "mount(2) syscall was never invoked, or ran successfully";
log::debug!("Unmount::mount_syscall_errno {}. libmount::mnt_context_get_syscall_errno returned error code: 0", err_msg);
None
}
errno => {
log::debug!("Unmount::mount_syscall_errno got mount(2) syscall error number");
Some(errno)
}
}
}
pub fn seq_unmount(&mut self) -> UMountIter<'_> {
UMountIter::new(self).unwrap()
}
pub fn is_dry_run(&self) -> bool {
let state = unsafe { libmount::mnt_context_is_fake(self.inner) == 1 };
log::debug!("Unmount::is_dry_run value: {:?}", state);
state
}
pub fn is_verbose(&self) -> bool {
let state = unsafe { libmount::mnt_context_is_verbose(self.inner) == 1 };
log::debug!("Unmount::is_verbose value: {:?}", state);
state
}
pub fn detaches_loop_device(&self) -> bool {
let state = unsafe { libmount::mnt_context_is_loopdel(self.inner) == 1 };
log::debug!("Unmount::detaches_loop_device value: {:?}", state);
state
}
pub fn disabled_path_canonicalization(&self) -> bool {
let state = unsafe { libmount::mnt_context_is_nocanonicalize(self.inner) == 1 };
log::debug!("Unmount::disabled_path_canonicalization value: {:?}", state);
state
}
pub fn disabled_mount_point_lookup(&self) -> bool {
let state = unsafe { libmount::mnt_context_is_swapmatch(self.inner) == 1 };
log::debug!("Unmount::disabled_mount_point_lookup value: {:?}", state);
state
}
pub fn has_called_umount_syscall(&self) -> bool {
let state = unsafe { libmount::mnt_context_syscall_called(self.inner) == 1 };
log::debug!("Unmount::has_called_umount_syscall value: {:?}", state);
state
}
pub fn has_disabled_helpers(&self) -> bool {
let state = unsafe { libmount::mnt_context_is_nohelpers(self.inner) == 1 };
log::debug!("Unmount::has_disabled_helpers value: {:?}", state);
state
}
pub fn has_run_umount_helper(&self) -> bool {
let state = unsafe { libmount::mnt_context_helper_executed(self.inner) == 1 };
log::debug!("Unmount::has_run_umount_helper value: {:?}", state);
state
}
pub fn does_not_update_utab(&self) -> bool {
let state = unsafe { libmount::mnt_context_is_nohelpers(self.inner) == 1 };
log::debug!("Unmount::does_not_update_utab value: {:?}", state);
state
}
pub fn does_lazy_unmount(&self) -> bool {
let state = unsafe { libmount::mnt_context_is_lazy(self.inner) == 1 };
log::debug!("Unmount::does_lazy_unmount value: {:?}", state);
state
}
pub fn forces_unmount(&self) -> bool {
let state = unsafe { libmount::mnt_context_is_force(self.inner) == 1 };
log::debug!("Unmount::forces_unmount value: {:?}", state);
state
}
pub fn on_fail_remounts_read_only(&self) -> bool {
let state = unsafe { libmount::mnt_context_is_rdonly_umount(self.inner) == 1 };
log::debug!("Unmount::on_fail_remounts_read_only value: {:?}", state);
state
}
}
impl AsRef<Unmount> for Unmount {
fn as_ref(&self) -> &Unmount {
self
}
}
impl Drop for Unmount {
fn drop(&mut self) {
log::debug!("Unmount::drop deallocating `Unmount` instance");
unsafe { libmount::mnt_free_context(self.inner) }
}
}