13da5c369Sopenharmony_ci#[cfg(target_os = "freebsd")] 23da5c369Sopenharmony_ciuse crate::Error; 33da5c369Sopenharmony_ciuse crate::{Errno, NixPath, Result}; 43da5c369Sopenharmony_ciuse libc::c_int; 53da5c369Sopenharmony_ci#[cfg(target_os = "freebsd")] 63da5c369Sopenharmony_ciuse libc::{c_char, c_uint, c_void}; 73da5c369Sopenharmony_ci#[cfg(target_os = "freebsd")] 83da5c369Sopenharmony_ciuse std::{ 93da5c369Sopenharmony_ci borrow::Cow, 103da5c369Sopenharmony_ci ffi::{CStr, CString}, 113da5c369Sopenharmony_ci fmt, io, 123da5c369Sopenharmony_ci marker::PhantomData, 133da5c369Sopenharmony_ci}; 143da5c369Sopenharmony_ci 153da5c369Sopenharmony_cilibc_bitflags!( 163da5c369Sopenharmony_ci /// Used with [`Nmount::nmount`]. 173da5c369Sopenharmony_ci pub struct MntFlags: c_int { 183da5c369Sopenharmony_ci /// ACL support enabled. 193da5c369Sopenharmony_ci #[cfg(any(target_os = "netbsd", target_os = "freebsd"))] 203da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 213da5c369Sopenharmony_ci MNT_ACLS; 223da5c369Sopenharmony_ci /// All I/O to the file system should be done asynchronously. 233da5c369Sopenharmony_ci MNT_ASYNC; 243da5c369Sopenharmony_ci /// dir should instead be a file system ID encoded as “FSID:val0:val1”. 253da5c369Sopenharmony_ci #[cfg(target_os = "freebsd")] 263da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 273da5c369Sopenharmony_ci MNT_BYFSID; 283da5c369Sopenharmony_ci /// Force a read-write mount even if the file system appears to be 293da5c369Sopenharmony_ci /// unclean. 303da5c369Sopenharmony_ci MNT_FORCE; 313da5c369Sopenharmony_ci /// GEOM journal support enabled. 323da5c369Sopenharmony_ci #[cfg(target_os = "freebsd")] 333da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 343da5c369Sopenharmony_ci MNT_GJOURNAL; 353da5c369Sopenharmony_ci /// MAC support for objects. 363da5c369Sopenharmony_ci #[cfg(any(target_os = "macos", target_os = "freebsd"))] 373da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 383da5c369Sopenharmony_ci MNT_MULTILABEL; 393da5c369Sopenharmony_ci /// Disable read clustering. 403da5c369Sopenharmony_ci #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] 413da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 423da5c369Sopenharmony_ci MNT_NOCLUSTERR; 433da5c369Sopenharmony_ci /// Disable write clustering. 443da5c369Sopenharmony_ci #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] 453da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 463da5c369Sopenharmony_ci MNT_NOCLUSTERW; 473da5c369Sopenharmony_ci /// Enable NFS version 4 ACLs. 483da5c369Sopenharmony_ci #[cfg(target_os = "freebsd")] 493da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 503da5c369Sopenharmony_ci MNT_NFS4ACLS; 513da5c369Sopenharmony_ci /// Do not update access times. 523da5c369Sopenharmony_ci MNT_NOATIME; 533da5c369Sopenharmony_ci /// Disallow program execution. 543da5c369Sopenharmony_ci MNT_NOEXEC; 553da5c369Sopenharmony_ci /// Do not honor setuid or setgid bits on files when executing them. 563da5c369Sopenharmony_ci MNT_NOSUID; 573da5c369Sopenharmony_ci /// Do not follow symlinks. 583da5c369Sopenharmony_ci #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] 593da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 603da5c369Sopenharmony_ci MNT_NOSYMFOLLOW; 613da5c369Sopenharmony_ci /// Mount read-only. 623da5c369Sopenharmony_ci MNT_RDONLY; 633da5c369Sopenharmony_ci /// Causes the vfs subsystem to update its data structures pertaining to 643da5c369Sopenharmony_ci /// the specified already mounted file system. 653da5c369Sopenharmony_ci MNT_RELOAD; 663da5c369Sopenharmony_ci /// Create a snapshot of the file system. 673da5c369Sopenharmony_ci /// 683da5c369Sopenharmony_ci /// See [mksnap_ffs(8)](https://www.freebsd.org/cgi/man.cgi?query=mksnap_ffs) 693da5c369Sopenharmony_ci #[cfg(any(target_os = "macos", target_os = "freebsd"))] 703da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 713da5c369Sopenharmony_ci MNT_SNAPSHOT; 723da5c369Sopenharmony_ci /// Using soft updates. 733da5c369Sopenharmony_ci #[cfg(any( 743da5c369Sopenharmony_ci target_os = "dragonfly", 753da5c369Sopenharmony_ci target_os = "freebsd", 763da5c369Sopenharmony_ci target_os = "netbsd", 773da5c369Sopenharmony_ci target_os = "openbsd" 783da5c369Sopenharmony_ci ))] 793da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 803da5c369Sopenharmony_ci MNT_SOFTDEP; 813da5c369Sopenharmony_ci /// Directories with the SUID bit set chown new files to their own 823da5c369Sopenharmony_ci /// owner. 833da5c369Sopenharmony_ci #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] 843da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 853da5c369Sopenharmony_ci MNT_SUIDDIR; 863da5c369Sopenharmony_ci /// All I/O to the file system should be done synchronously. 873da5c369Sopenharmony_ci MNT_SYNCHRONOUS; 883da5c369Sopenharmony_ci /// Union with underlying fs. 893da5c369Sopenharmony_ci #[cfg(any( 903da5c369Sopenharmony_ci target_os = "macos", 913da5c369Sopenharmony_ci target_os = "freebsd", 923da5c369Sopenharmony_ci target_os = "netbsd" 933da5c369Sopenharmony_ci ))] 943da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 953da5c369Sopenharmony_ci MNT_UNION; 963da5c369Sopenharmony_ci /// Indicates that the mount command is being applied to an already 973da5c369Sopenharmony_ci /// mounted file system. 983da5c369Sopenharmony_ci MNT_UPDATE; 993da5c369Sopenharmony_ci /// Check vnode use counts. 1003da5c369Sopenharmony_ci #[cfg(target_os = "freebsd")] 1013da5c369Sopenharmony_ci #[cfg_attr(docsrs, doc(cfg(all())))] 1023da5c369Sopenharmony_ci MNT_NONBUSY; 1033da5c369Sopenharmony_ci } 1043da5c369Sopenharmony_ci); 1053da5c369Sopenharmony_ci 1063da5c369Sopenharmony_ci/// The Error type of [`Nmount::nmount`]. 1073da5c369Sopenharmony_ci/// 1083da5c369Sopenharmony_ci/// It wraps an [`Errno`], but also may contain an additional message returned 1093da5c369Sopenharmony_ci/// by `nmount(2)`. 1103da5c369Sopenharmony_ci#[cfg(target_os = "freebsd")] 1113da5c369Sopenharmony_ci#[derive(Debug)] 1123da5c369Sopenharmony_cipub struct NmountError { 1133da5c369Sopenharmony_ci errno: Error, 1143da5c369Sopenharmony_ci errmsg: Option<String>, 1153da5c369Sopenharmony_ci} 1163da5c369Sopenharmony_ci 1173da5c369Sopenharmony_ci#[cfg(target_os = "freebsd")] 1183da5c369Sopenharmony_ciimpl NmountError { 1193da5c369Sopenharmony_ci /// Returns the additional error string sometimes generated by `nmount(2)`. 1203da5c369Sopenharmony_ci pub fn errmsg(&self) -> Option<&str> { 1213da5c369Sopenharmony_ci self.errmsg.as_deref() 1223da5c369Sopenharmony_ci } 1233da5c369Sopenharmony_ci 1243da5c369Sopenharmony_ci /// Returns the inner [`Error`] 1253da5c369Sopenharmony_ci pub const fn error(&self) -> Error { 1263da5c369Sopenharmony_ci self.errno 1273da5c369Sopenharmony_ci } 1283da5c369Sopenharmony_ci 1293da5c369Sopenharmony_ci fn new(error: Error, errmsg: Option<&CStr>) -> Self { 1303da5c369Sopenharmony_ci Self { 1313da5c369Sopenharmony_ci errno: error, 1323da5c369Sopenharmony_ci errmsg: errmsg.map(CStr::to_string_lossy).map(Cow::into_owned), 1333da5c369Sopenharmony_ci } 1343da5c369Sopenharmony_ci } 1353da5c369Sopenharmony_ci} 1363da5c369Sopenharmony_ci 1373da5c369Sopenharmony_ci#[cfg(target_os = "freebsd")] 1383da5c369Sopenharmony_ciimpl std::error::Error for NmountError {} 1393da5c369Sopenharmony_ci 1403da5c369Sopenharmony_ci#[cfg(target_os = "freebsd")] 1413da5c369Sopenharmony_ciimpl fmt::Display for NmountError { 1423da5c369Sopenharmony_ci fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 1433da5c369Sopenharmony_ci if let Some(errmsg) = &self.errmsg { 1443da5c369Sopenharmony_ci write!(f, "{:?}: {}: {}", self.errno, errmsg, self.errno.desc()) 1453da5c369Sopenharmony_ci } else { 1463da5c369Sopenharmony_ci write!(f, "{:?}: {}", self.errno, self.errno.desc()) 1473da5c369Sopenharmony_ci } 1483da5c369Sopenharmony_ci } 1493da5c369Sopenharmony_ci} 1503da5c369Sopenharmony_ci 1513da5c369Sopenharmony_ci#[cfg(target_os = "freebsd")] 1523da5c369Sopenharmony_ciimpl From<NmountError> for io::Error { 1533da5c369Sopenharmony_ci fn from(err: NmountError) -> Self { 1543da5c369Sopenharmony_ci err.errno.into() 1553da5c369Sopenharmony_ci } 1563da5c369Sopenharmony_ci} 1573da5c369Sopenharmony_ci 1583da5c369Sopenharmony_ci/// Result type of [`Nmount::nmount`]. 1593da5c369Sopenharmony_ci#[cfg(target_os = "freebsd")] 1603da5c369Sopenharmony_cipub type NmountResult = std::result::Result<(), NmountError>; 1613da5c369Sopenharmony_ci 1623da5c369Sopenharmony_ci/// Mount a FreeBSD file system. 1633da5c369Sopenharmony_ci/// 1643da5c369Sopenharmony_ci/// The `nmount(2)` system call works similarly to the `mount(8)` program; it 1653da5c369Sopenharmony_ci/// takes its options as a series of name-value pairs. Most of the values are 1663da5c369Sopenharmony_ci/// strings, as are all of the names. The `Nmount` structure builds up an 1673da5c369Sopenharmony_ci/// argument list and then executes the syscall. 1683da5c369Sopenharmony_ci/// 1693da5c369Sopenharmony_ci/// # Examples 1703da5c369Sopenharmony_ci/// 1713da5c369Sopenharmony_ci/// To mount `target` onto `mountpoint` with `nullfs`: 1723da5c369Sopenharmony_ci/// ``` 1733da5c369Sopenharmony_ci/// # use nix::unistd::Uid; 1743da5c369Sopenharmony_ci/// # use ::sysctl::{CtlValue, Sysctl}; 1753da5c369Sopenharmony_ci/// # let ctl = ::sysctl::Ctl::new("vfs.usermount").unwrap(); 1763da5c369Sopenharmony_ci/// # if !Uid::current().is_root() && CtlValue::Int(0) == ctl.value().unwrap() { 1773da5c369Sopenharmony_ci/// # return; 1783da5c369Sopenharmony_ci/// # }; 1793da5c369Sopenharmony_ci/// use nix::mount::{MntFlags, Nmount, unmount}; 1803da5c369Sopenharmony_ci/// use std::ffi::CString; 1813da5c369Sopenharmony_ci/// use tempfile::tempdir; 1823da5c369Sopenharmony_ci/// 1833da5c369Sopenharmony_ci/// let mountpoint = tempdir().unwrap(); 1843da5c369Sopenharmony_ci/// let target = tempdir().unwrap(); 1853da5c369Sopenharmony_ci/// 1863da5c369Sopenharmony_ci/// let fstype = CString::new("fstype").unwrap(); 1873da5c369Sopenharmony_ci/// let nullfs = CString::new("nullfs").unwrap(); 1883da5c369Sopenharmony_ci/// Nmount::new() 1893da5c369Sopenharmony_ci/// .str_opt(&fstype, &nullfs) 1903da5c369Sopenharmony_ci/// .str_opt_owned("fspath", mountpoint.path().to_str().unwrap()) 1913da5c369Sopenharmony_ci/// .str_opt_owned("target", target.path().to_str().unwrap()) 1923da5c369Sopenharmony_ci/// .nmount(MntFlags::empty()).unwrap(); 1933da5c369Sopenharmony_ci/// 1943da5c369Sopenharmony_ci/// unmount(mountpoint.path(), MntFlags::empty()).unwrap(); 1953da5c369Sopenharmony_ci/// ``` 1963da5c369Sopenharmony_ci/// 1973da5c369Sopenharmony_ci/// # See Also 1983da5c369Sopenharmony_ci/// * [`nmount(2)`](https://www.freebsd.org/cgi/man.cgi?query=nmount) 1993da5c369Sopenharmony_ci/// * [`nullfs(5)`](https://www.freebsd.org/cgi/man.cgi?query=nullfs) 2003da5c369Sopenharmony_ci#[cfg(target_os = "freebsd")] 2013da5c369Sopenharmony_ci#[cfg_attr(docsrs, doc(cfg(all())))] 2023da5c369Sopenharmony_ci#[derive(Debug, Default)] 2033da5c369Sopenharmony_cipub struct Nmount<'a> { 2043da5c369Sopenharmony_ci // n.b. notgull: In reality, this is a list that contains 2053da5c369Sopenharmony_ci // both mutable and immutable pointers. 2063da5c369Sopenharmony_ci // Be careful using this. 2073da5c369Sopenharmony_ci iov: Vec<libc::iovec>, 2083da5c369Sopenharmony_ci is_owned: Vec<bool>, 2093da5c369Sopenharmony_ci marker: PhantomData<&'a ()>, 2103da5c369Sopenharmony_ci} 2113da5c369Sopenharmony_ci 2123da5c369Sopenharmony_ci#[cfg(target_os = "freebsd")] 2133da5c369Sopenharmony_ci#[cfg_attr(docsrs, doc(cfg(all())))] 2143da5c369Sopenharmony_ciimpl<'a> Nmount<'a> { 2153da5c369Sopenharmony_ci /// Helper function to push a slice onto the `iov` array. 2163da5c369Sopenharmony_ci fn push_slice(&mut self, val: &'a [u8], is_owned: bool) { 2173da5c369Sopenharmony_ci self.iov.push(libc::iovec { 2183da5c369Sopenharmony_ci iov_base: val.as_ptr() as *mut _, 2193da5c369Sopenharmony_ci iov_len: val.len(), 2203da5c369Sopenharmony_ci }); 2213da5c369Sopenharmony_ci self.is_owned.push(is_owned); 2223da5c369Sopenharmony_ci } 2233da5c369Sopenharmony_ci 2243da5c369Sopenharmony_ci /// Helper function to push a pointer and its length onto the `iov` array. 2253da5c369Sopenharmony_ci fn push_pointer_and_length( 2263da5c369Sopenharmony_ci &mut self, 2273da5c369Sopenharmony_ci val: *const u8, 2283da5c369Sopenharmony_ci len: usize, 2293da5c369Sopenharmony_ci is_owned: bool, 2303da5c369Sopenharmony_ci ) { 2313da5c369Sopenharmony_ci self.iov.push(libc::iovec { 2323da5c369Sopenharmony_ci iov_base: val as *mut _, 2333da5c369Sopenharmony_ci iov_len: len, 2343da5c369Sopenharmony_ci }); 2353da5c369Sopenharmony_ci self.is_owned.push(is_owned); 2363da5c369Sopenharmony_ci } 2373da5c369Sopenharmony_ci 2383da5c369Sopenharmony_ci /// Helper function to push a `nix` path as owned. 2393da5c369Sopenharmony_ci fn push_nix_path<P: ?Sized + NixPath>(&mut self, val: &P) { 2403da5c369Sopenharmony_ci val.with_nix_path(|s| { 2413da5c369Sopenharmony_ci let len = s.to_bytes_with_nul().len(); 2423da5c369Sopenharmony_ci let ptr = s.to_owned().into_raw() as *const u8; 2433da5c369Sopenharmony_ci 2443da5c369Sopenharmony_ci self.push_pointer_and_length(ptr, len, true); 2453da5c369Sopenharmony_ci }) 2463da5c369Sopenharmony_ci .unwrap(); 2473da5c369Sopenharmony_ci } 2483da5c369Sopenharmony_ci 2493da5c369Sopenharmony_ci /// Add an opaque mount option. 2503da5c369Sopenharmony_ci /// 2513da5c369Sopenharmony_ci /// Some file systems take binary-valued mount options. They can be set 2523da5c369Sopenharmony_ci /// with this method. 2533da5c369Sopenharmony_ci /// 2543da5c369Sopenharmony_ci /// # Safety 2553da5c369Sopenharmony_ci /// 2563da5c369Sopenharmony_ci /// Unsafe because it will cause `Nmount::nmount` to dereference a raw 2573da5c369Sopenharmony_ci /// pointer. The user is responsible for ensuring that `val` is valid and 2583da5c369Sopenharmony_ci /// its lifetime outlives `self`! An easy way to do that is to give the 2593da5c369Sopenharmony_ci /// value a larger scope than `name` 2603da5c369Sopenharmony_ci /// 2613da5c369Sopenharmony_ci /// # Examples 2623da5c369Sopenharmony_ci /// ``` 2633da5c369Sopenharmony_ci /// use libc::c_void; 2643da5c369Sopenharmony_ci /// use nix::mount::Nmount; 2653da5c369Sopenharmony_ci /// use std::ffi::CString; 2663da5c369Sopenharmony_ci /// use std::mem; 2673da5c369Sopenharmony_ci /// 2683da5c369Sopenharmony_ci /// // Note that flags outlives name 2693da5c369Sopenharmony_ci /// let mut flags: u32 = 0xdeadbeef; 2703da5c369Sopenharmony_ci /// let name = CString::new("flags").unwrap(); 2713da5c369Sopenharmony_ci /// let p = &mut flags as *mut u32 as *mut c_void; 2723da5c369Sopenharmony_ci /// let len = mem::size_of_val(&flags); 2733da5c369Sopenharmony_ci /// let mut nmount = Nmount::new(); 2743da5c369Sopenharmony_ci /// unsafe { nmount.mut_ptr_opt(&name, p, len) }; 2753da5c369Sopenharmony_ci /// ``` 2763da5c369Sopenharmony_ci pub unsafe fn mut_ptr_opt( 2773da5c369Sopenharmony_ci &mut self, 2783da5c369Sopenharmony_ci name: &'a CStr, 2793da5c369Sopenharmony_ci val: *mut c_void, 2803da5c369Sopenharmony_ci len: usize, 2813da5c369Sopenharmony_ci ) -> &mut Self { 2823da5c369Sopenharmony_ci self.push_slice(name.to_bytes_with_nul(), false); 2833da5c369Sopenharmony_ci self.push_pointer_and_length(val.cast(), len, false); 2843da5c369Sopenharmony_ci self 2853da5c369Sopenharmony_ci } 2863da5c369Sopenharmony_ci 2873da5c369Sopenharmony_ci /// Add a mount option that does not take a value. 2883da5c369Sopenharmony_ci /// 2893da5c369Sopenharmony_ci /// # Examples 2903da5c369Sopenharmony_ci /// ``` 2913da5c369Sopenharmony_ci /// use nix::mount::Nmount; 2923da5c369Sopenharmony_ci /// use std::ffi::CString; 2933da5c369Sopenharmony_ci /// 2943da5c369Sopenharmony_ci /// let read_only = CString::new("ro").unwrap(); 2953da5c369Sopenharmony_ci /// Nmount::new() 2963da5c369Sopenharmony_ci /// .null_opt(&read_only); 2973da5c369Sopenharmony_ci /// ``` 2983da5c369Sopenharmony_ci pub fn null_opt(&mut self, name: &'a CStr) -> &mut Self { 2993da5c369Sopenharmony_ci self.push_slice(name.to_bytes_with_nul(), false); 3003da5c369Sopenharmony_ci self.push_slice(&[], false); 3013da5c369Sopenharmony_ci self 3023da5c369Sopenharmony_ci } 3033da5c369Sopenharmony_ci 3043da5c369Sopenharmony_ci /// Add a mount option that does not take a value, but whose name must be 3053da5c369Sopenharmony_ci /// owned. 3063da5c369Sopenharmony_ci /// 3073da5c369Sopenharmony_ci /// 3083da5c369Sopenharmony_ci /// This has higher runtime cost than [`Nmount::null_opt`], but is useful 3093da5c369Sopenharmony_ci /// when the name's lifetime doesn't outlive the `Nmount`, or it's a 3103da5c369Sopenharmony_ci /// different string type than `CStr`. 3113da5c369Sopenharmony_ci /// 3123da5c369Sopenharmony_ci /// # Examples 3133da5c369Sopenharmony_ci /// ``` 3143da5c369Sopenharmony_ci /// use nix::mount::Nmount; 3153da5c369Sopenharmony_ci /// 3163da5c369Sopenharmony_ci /// let read_only = "ro"; 3173da5c369Sopenharmony_ci /// let mut nmount: Nmount<'static> = Nmount::new(); 3183da5c369Sopenharmony_ci /// nmount.null_opt_owned(read_only); 3193da5c369Sopenharmony_ci /// ``` 3203da5c369Sopenharmony_ci pub fn null_opt_owned<P: ?Sized + NixPath>( 3213da5c369Sopenharmony_ci &mut self, 3223da5c369Sopenharmony_ci name: &P, 3233da5c369Sopenharmony_ci ) -> &mut Self { 3243da5c369Sopenharmony_ci self.push_nix_path(name); 3253da5c369Sopenharmony_ci self.push_slice(&[], false); 3263da5c369Sopenharmony_ci self 3273da5c369Sopenharmony_ci } 3283da5c369Sopenharmony_ci 3293da5c369Sopenharmony_ci /// Add a mount option as a [`CStr`]. 3303da5c369Sopenharmony_ci /// 3313da5c369Sopenharmony_ci /// # Examples 3323da5c369Sopenharmony_ci /// ``` 3333da5c369Sopenharmony_ci /// use nix::mount::Nmount; 3343da5c369Sopenharmony_ci /// use std::ffi::CString; 3353da5c369Sopenharmony_ci /// 3363da5c369Sopenharmony_ci /// let fstype = CString::new("fstype").unwrap(); 3373da5c369Sopenharmony_ci /// let nullfs = CString::new("nullfs").unwrap(); 3383da5c369Sopenharmony_ci /// Nmount::new() 3393da5c369Sopenharmony_ci /// .str_opt(&fstype, &nullfs); 3403da5c369Sopenharmony_ci /// ``` 3413da5c369Sopenharmony_ci pub fn str_opt(&mut self, name: &'a CStr, val: &'a CStr) -> &mut Self { 3423da5c369Sopenharmony_ci self.push_slice(name.to_bytes_with_nul(), false); 3433da5c369Sopenharmony_ci self.push_slice(val.to_bytes_with_nul(), false); 3443da5c369Sopenharmony_ci self 3453da5c369Sopenharmony_ci } 3463da5c369Sopenharmony_ci 3473da5c369Sopenharmony_ci /// Add a mount option as an owned string. 3483da5c369Sopenharmony_ci /// 3493da5c369Sopenharmony_ci /// This has higher runtime cost than [`Nmount::str_opt`], but is useful 3503da5c369Sopenharmony_ci /// when the value's lifetime doesn't outlive the `Nmount`, or it's a 3513da5c369Sopenharmony_ci /// different string type than `CStr`. 3523da5c369Sopenharmony_ci /// 3533da5c369Sopenharmony_ci /// # Examples 3543da5c369Sopenharmony_ci /// ``` 3553da5c369Sopenharmony_ci /// use nix::mount::Nmount; 3563da5c369Sopenharmony_ci /// use std::path::Path; 3573da5c369Sopenharmony_ci /// 3583da5c369Sopenharmony_ci /// let mountpoint = Path::new("/mnt"); 3593da5c369Sopenharmony_ci /// Nmount::new() 3603da5c369Sopenharmony_ci /// .str_opt_owned("fspath", mountpoint.to_str().unwrap()); 3613da5c369Sopenharmony_ci /// ``` 3623da5c369Sopenharmony_ci pub fn str_opt_owned<P1, P2>(&mut self, name: &P1, val: &P2) -> &mut Self 3633da5c369Sopenharmony_ci where 3643da5c369Sopenharmony_ci P1: ?Sized + NixPath, 3653da5c369Sopenharmony_ci P2: ?Sized + NixPath, 3663da5c369Sopenharmony_ci { 3673da5c369Sopenharmony_ci self.push_nix_path(name); 3683da5c369Sopenharmony_ci self.push_nix_path(val); 3693da5c369Sopenharmony_ci self 3703da5c369Sopenharmony_ci } 3713da5c369Sopenharmony_ci 3723da5c369Sopenharmony_ci /// Create a new `Nmount` struct with no options 3733da5c369Sopenharmony_ci pub fn new() -> Self { 3743da5c369Sopenharmony_ci Self::default() 3753da5c369Sopenharmony_ci } 3763da5c369Sopenharmony_ci 3773da5c369Sopenharmony_ci /// Actually mount the file system. 3783da5c369Sopenharmony_ci pub fn nmount(&mut self, flags: MntFlags) -> NmountResult { 3793da5c369Sopenharmony_ci const ERRMSG_NAME: &[u8] = b"errmsg\0"; 3803da5c369Sopenharmony_ci let mut errmsg = vec![0u8; 255]; 3813da5c369Sopenharmony_ci 3823da5c369Sopenharmony_ci // nmount can return extra error information via a "errmsg" return 3833da5c369Sopenharmony_ci // argument. 3843da5c369Sopenharmony_ci self.push_slice(ERRMSG_NAME, false); 3853da5c369Sopenharmony_ci 3863da5c369Sopenharmony_ci // SAFETY: we are pushing a mutable iovec here, so we can't use 3873da5c369Sopenharmony_ci // the above method 3883da5c369Sopenharmony_ci self.iov.push(libc::iovec { 3893da5c369Sopenharmony_ci iov_base: errmsg.as_mut_ptr() as *mut c_void, 3903da5c369Sopenharmony_ci iov_len: errmsg.len(), 3913da5c369Sopenharmony_ci }); 3923da5c369Sopenharmony_ci 3933da5c369Sopenharmony_ci let niov = self.iov.len() as c_uint; 3943da5c369Sopenharmony_ci let iovp = self.iov.as_mut_ptr() as *mut libc::iovec; 3953da5c369Sopenharmony_ci let res = unsafe { libc::nmount(iovp, niov, flags.bits) }; 3963da5c369Sopenharmony_ci match Errno::result(res) { 3973da5c369Sopenharmony_ci Ok(_) => Ok(()), 3983da5c369Sopenharmony_ci Err(error) => { 3993da5c369Sopenharmony_ci let errmsg = match errmsg.iter().position(|&x| x == 0) { 4003da5c369Sopenharmony_ci None => None, 4013da5c369Sopenharmony_ci Some(0) => None, 4023da5c369Sopenharmony_ci Some(n) => { 4033da5c369Sopenharmony_ci let sl = &errmsg[0..n + 1]; 4043da5c369Sopenharmony_ci Some(CStr::from_bytes_with_nul(sl).unwrap()) 4053da5c369Sopenharmony_ci } 4063da5c369Sopenharmony_ci }; 4073da5c369Sopenharmony_ci Err(NmountError::new(error, errmsg)) 4083da5c369Sopenharmony_ci } 4093da5c369Sopenharmony_ci } 4103da5c369Sopenharmony_ci } 4113da5c369Sopenharmony_ci} 4123da5c369Sopenharmony_ci 4133da5c369Sopenharmony_ci#[cfg(target_os = "freebsd")] 4143da5c369Sopenharmony_ciimpl<'a> Drop for Nmount<'a> { 4153da5c369Sopenharmony_ci fn drop(&mut self) { 4163da5c369Sopenharmony_ci for (iov, is_owned) in self.iov.iter().zip(self.is_owned.iter()) { 4173da5c369Sopenharmony_ci if *is_owned { 4183da5c369Sopenharmony_ci // Free the owned string. Safe because we recorded ownership, 4193da5c369Sopenharmony_ci // and Nmount does not implement Clone. 4203da5c369Sopenharmony_ci unsafe { 4213da5c369Sopenharmony_ci drop(CString::from_raw(iov.iov_base as *mut c_char)); 4223da5c369Sopenharmony_ci } 4233da5c369Sopenharmony_ci } 4243da5c369Sopenharmony_ci } 4253da5c369Sopenharmony_ci } 4263da5c369Sopenharmony_ci} 4273da5c369Sopenharmony_ci 4283da5c369Sopenharmony_ci/// Unmount the file system mounted at `mountpoint`. 4293da5c369Sopenharmony_ci/// 4303da5c369Sopenharmony_ci/// Useful flags include 4313da5c369Sopenharmony_ci/// * `MNT_FORCE` - Unmount even if still in use. 4323da5c369Sopenharmony_ci#[cfg_attr( 4333da5c369Sopenharmony_ci target_os = "freebsd", 4343da5c369Sopenharmony_ci doc = " 4353da5c369Sopenharmony_ci* `MNT_BYFSID` - `mountpoint` is not a path, but a file system ID 4363da5c369Sopenharmony_ci encoded as `FSID:val0:val1`, where `val0` and `val1` 4373da5c369Sopenharmony_ci are the contents of the `fsid_t val[]` array in decimal. 4383da5c369Sopenharmony_ci The file system that has the specified file system ID 4393da5c369Sopenharmony_ci will be unmounted. See 4403da5c369Sopenharmony_ci [`statfs`](crate::sys::statfs::statfs) to determine the 4413da5c369Sopenharmony_ci `fsid`. 4423da5c369Sopenharmony_ci" 4433da5c369Sopenharmony_ci)] 4443da5c369Sopenharmony_cipub fn unmount<P>(mountpoint: &P, flags: MntFlags) -> Result<()> 4453da5c369Sopenharmony_ciwhere 4463da5c369Sopenharmony_ci P: ?Sized + NixPath, 4473da5c369Sopenharmony_ci{ 4483da5c369Sopenharmony_ci let res = mountpoint.with_nix_path(|cstr| unsafe { 4493da5c369Sopenharmony_ci libc::unmount(cstr.as_ptr(), flags.bits) 4503da5c369Sopenharmony_ci })?; 4513da5c369Sopenharmony_ci 4523da5c369Sopenharmony_ci Errno::result(res).map(drop) 4533da5c369Sopenharmony_ci} 454