From 7de4c75ae0509ae91fd6fdede515fcf623cc7062 Mon Sep 17 00:00:00 2001 From: owl Date: Thu, 28 Mar 2024 23:39:11 +0800 Subject: [PATCH 01/12] feat: introduce macos mount API support --- build.rs | 1 + src/mount/apple.rs | 116 +++++++++++++++++++++++++++++++++++++++++++++ src/mount/mod.rs | 10 +++- 3 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 src/mount/apple.rs diff --git a/build.rs b/build.rs index ecadc04f5d..34953cc661 100644 --- a/build.rs +++ b/build.rs @@ -19,6 +19,7 @@ fn main() { // cfg aliases we would like to use apple_targets: { any(ios, macos, watchos, tvos) }, bsd: { any(freebsd, dragonfly, netbsd, openbsd, apple_targets) }, + bsd_without_macos: { any(freebsd, dragonfly, netbsd, openbsd) }, linux_android: { any(android, linux) }, freebsdlike: { any(dragonfly, freebsd) }, netbsdlike: { any(netbsd, openbsd) }, diff --git a/src/mount/apple.rs b/src/mount/apple.rs new file mode 100644 index 0000000000..d81124d51f --- /dev/null +++ b/src/mount/apple.rs @@ -0,0 +1,116 @@ +use crate::{Errno, NixPath, Result}; +use libc::c_int; + +libc_bitflags!( + /// Used with [`Nmount::nmount`]. + pub struct MntFlags: c_int { + /// All I/O to the file system should be done asynchronously. + MNT_ASYNC; + /// Force a read-write mount even if the file system appears to be + /// unclean. + MNT_FORCE; + /// MAC support for objects. + MNT_MULTILABEL; + /// Disable read clustering. + #[cfg(freebsdlike)] + MNT_NOCLUSTERR; + /// Disable write clustering. + #[cfg(freebsdlike)] + MNT_NOCLUSTERW; + /// Do not update access times. + MNT_NOATIME; + /// Disallow program execution. + MNT_NOEXEC; + /// Do not honor setuid or setgid bits on files when executing them. + MNT_NOSUID; + /// Mount read-only. + MNT_RDONLY; + /// Causes the vfs subsystem to update its data structures pertaining to + /// the specified already mounted file system. + MNT_RELOAD; + /// Create a snapshot of the file system. + /// + MNT_SNAPSHOT; + /// All I/O to the file system should be done synchronously. + MNT_SYNCHRONOUS; + /// Union with underlying fs. + MNT_UNION; + /// Indicates that the mount command is being applied to an already + /// mounted file system. + MNT_UPDATE; + } +); + + +libc_bitflags!( + /// Used with [`mount`]. + pub struct MsFlags: c_int { + MS_ASYNC; + MS_INVALIDATE; + MS_SYNC; + MS_KILLPAGES; + MS_DEACTIVATE; + } +); + + +/// Mount a file system. +/// +/// # Arguments +/// - `source` - Specifies the file system. e.g. `/dev/sd0`. +/// - `target` - Specifies the destination. e.g. `/mnt`. +/// - `flags` - Optional flags controlling the mount. +/// - `data` - Optional file system specific data. +/// +pub fn mount< + P1: ?Sized + NixPath, + P2: ?Sized + NixPath, + P3: ?Sized + NixPath, + P4: ?Sized + NixPath, +>( + source: Option<&P1>, + target: &P2, + fstype: Option<&P3>, + flags: MsFlags, + data: Option<&P4>, +) -> Result<()> { + fn with_opt_nix_path(p: Option<&P>, f: F) -> Result + where + P: ?Sized + NixPath, + F: FnOnce(*const libc::c_char) -> T, + { + match p { + Some(path) => path.with_nix_path(|p_str| f(p_str.as_ptr())), + None => Ok(f(std::ptr::null())), + } + } + + let res = with_opt_nix_path(source, |s| { + target.with_nix_path(|t| { + with_opt_nix_path(fstype, |_| { + with_opt_nix_path(data, |d| unsafe { + libc::mount( + s, + t.as_ptr(), + flags.bits(), + d as *mut libc::c_void, + ) + }) + }) + }) + })????; + + Errno::result(res).map(drop) +} + +/// Unmount the file system mounted at `target`. +pub fn unmount

(mountpoint: &P, flags: MntFlags) -> Result<()> +where + P: ?Sized + NixPath, +{ + let res = mountpoint.with_nix_path(|cstr| unsafe { + libc::unmount(cstr.as_ptr(), flags.bits()) + })?; + + Errno::result(res).map(drop) +} diff --git a/src/mount/mod.rs b/src/mount/mod.rs index 8caf27f7df..7213447677 100644 --- a/src/mount/mod.rs +++ b/src/mount/mod.rs @@ -5,8 +5,14 @@ mod linux; #[cfg(linux_android)] pub use self::linux::*; -#[cfg(bsd)] +#[cfg(bsd_without_macos)] mod bsd; -#[cfg(bsd)] +#[cfg(bsd_without_macos)] pub use self::bsd::*; + +#[cfg(apple_targets)] +mod apple; + +#[cfg(apple_targets)] +pub use self::apple::*; \ No newline at end of file From 0da612d4fc287eedb8125e5338a4ac2639ededf9 Mon Sep 17 00:00:00 2001 From: owl Date: Fri, 29 Mar 2024 16:01:46 +0800 Subject: [PATCH 02/12] feat: add doc comment --- src/mount/apple.rs | 51 ++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/src/mount/apple.rs b/src/mount/apple.rs index d81124d51f..af0302b7c1 100644 --- a/src/mount/apple.rs +++ b/src/mount/apple.rs @@ -4,6 +4,36 @@ use libc::c_int; libc_bitflags!( /// Used with [`Nmount::nmount`]. pub struct MntFlags: c_int { + /// Do not interpret special files on the filesystem. + MNT_NODEV; + /// file system supports content protection + MNT_CPROTECT; + /// filesystem is stored locally + MNT_QUARANTINE; + /// filesystem is stored locally + MNT_LOCAL; + /// quotas are enabled on filesystem + MNT_QUOTA; + /// identifies the root filesystem + MNT_ROOTFS; + /// FS supports volfs (deprecated flag in Mac OS X 10.5) + MNT_DOVOLFS; + /// file system is not appropriate path to user data + MNT_DONTBROWSE; + /// VFS will ignore ownership information on filesystem objects + MNT_IGNORE_OWNERSHIP; + /// filesystem was mounted by automounter + MNT_AUTOMOUNTED; + /// filesystem is journaled + MNT_JOURNALED; + /// Don't allow user extended attributes + MNT_NOUSERXATTR; + /// filesystem should defer writes + MNT_DEFWRITE; + /// don't block unmount if not responding + MNT_NOBLOCK; + /// file system is exported + MNT_EXPORTED; /// All I/O to the file system should be done asynchronously. MNT_ASYNC; /// Force a read-write mount even if the file system appears to be @@ -11,12 +41,6 @@ libc_bitflags!( MNT_FORCE; /// MAC support for objects. MNT_MULTILABEL; - /// Disable read clustering. - #[cfg(freebsdlike)] - MNT_NOCLUSTERR; - /// Disable write clustering. - #[cfg(freebsdlike)] - MNT_NOCLUSTERW; /// Do not update access times. MNT_NOATIME; /// Disallow program execution. @@ -41,19 +65,6 @@ libc_bitflags!( } ); - -libc_bitflags!( - /// Used with [`mount`]. - pub struct MsFlags: c_int { - MS_ASYNC; - MS_INVALIDATE; - MS_SYNC; - MS_KILLPAGES; - MS_DEACTIVATE; - } -); - - /// Mount a file system. /// /// # Arguments @@ -71,7 +82,7 @@ pub fn mount< source: Option<&P1>, target: &P2, fstype: Option<&P3>, - flags: MsFlags, + flags: MntFlags, data: Option<&P4>, ) -> Result<()> { fn with_opt_nix_path(p: Option<&P>, f: F) -> Result From 298111ba0141180209545cec308d0aa6d33eb28a Mon Sep 17 00:00:00 2001 From: owl Date: Sun, 31 Mar 2024 15:13:07 +0800 Subject: [PATCH 03/12] feat: fix code --- src/mount/apple.rs | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/mount/apple.rs b/src/mount/apple.rs index af0302b7c1..4a46795bf6 100644 --- a/src/mount/apple.rs +++ b/src/mount/apple.rs @@ -73,17 +73,17 @@ libc_bitflags!( /// - `flags` - Optional flags controlling the mount. /// - `data` - Optional file system specific data. /// +/// # see also +/// [`mount`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mount.2.html] pub fn mount< P1: ?Sized + NixPath, P2: ?Sized + NixPath, P3: ?Sized + NixPath, - P4: ?Sized + NixPath, >( - source: Option<&P1>, + source: &P1, target: &P2, - fstype: Option<&P3>, flags: MntFlags, - data: Option<&P4>, + data: Option<&P3>, ) -> Result<()> { fn with_opt_nix_path(p: Option<&P>, f: F) -> Result where @@ -96,26 +96,24 @@ pub fn mount< } } - let res = with_opt_nix_path(source, |s| { + let res = source.with_nix_path(|s| target.with_nix_path(|t| { - with_opt_nix_path(fstype, |_| { - with_opt_nix_path(data, |d| unsafe { - libc::mount( - s, - t.as_ptr(), - flags.bits(), - d as *mut libc::c_void, - ) - }) + with_opt_nix_path(data, |d| unsafe { + println!("mounting {:?} to {:?}", s, t); + libc::mount( + s.as_ptr(), + t.as_ptr(), + flags.bits(), + d as *mut libc::c_void, + ) }) - }) - })????; + }))???; Errno::result(res).map(drop) } -/// Unmount the file system mounted at `target`. -pub fn unmount

(mountpoint: &P, flags: MntFlags) -> Result<()> +/// Umount the file system mounted at `target`. +pub fn umount

(mountpoint: &P, flags: MntFlags) -> Result<()> where P: ?Sized + NixPath, { From 6bc2472e9eea0a4580a28feabdeb7562d1716760 Mon Sep 17 00:00:00 2001 From: owl Date: Sun, 31 Mar 2024 15:16:16 +0800 Subject: [PATCH 04/12] feat: fix code --- src/mount/apple.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mount/apple.rs b/src/mount/apple.rs index 4a46795bf6..9dde3e5ba7 100644 --- a/src/mount/apple.rs +++ b/src/mount/apple.rs @@ -74,7 +74,7 @@ libc_bitflags!( /// - `data` - Optional file system specific data. /// /// # see also -/// [`mount`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mount.2.html] +/// [`mount`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mount.2.html) pub fn mount< P1: ?Sized + NixPath, P2: ?Sized + NixPath, From 86520a5d61a55300203248e6171926a7465fc70d Mon Sep 17 00:00:00 2001 From: owl Date: Tue, 2 Apr 2024 11:45:31 +0800 Subject: [PATCH 05/12] feat: fix code --- src/mount/apple.rs | 18 +++++++----------- src/mount/mod.rs | 2 +- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/mount/apple.rs b/src/mount/apple.rs index 9dde3e5ba7..9f9fccf2bf 100644 --- a/src/mount/apple.rs +++ b/src/mount/apple.rs @@ -2,13 +2,13 @@ use crate::{Errno, NixPath, Result}; use libc::c_int; libc_bitflags!( - /// Used with [`Nmount::nmount`]. + /// Used with [`mount()`] and [`unmount()`]. pub struct MntFlags: c_int { /// Do not interpret special files on the filesystem. MNT_NODEV; - /// file system supports content protection + /// Enable data protection on the filesystem if the filesystem is configured for it. MNT_CPROTECT; - /// filesystem is stored locally + /// file system is quarantined MNT_QUARANTINE; /// filesystem is stored locally MNT_LOCAL; @@ -16,8 +16,6 @@ libc_bitflags!( MNT_QUOTA; /// identifies the root filesystem MNT_ROOTFS; - /// FS supports volfs (deprecated flag in Mac OS X 10.5) - MNT_DOVOLFS; /// file system is not appropriate path to user data MNT_DONTBROWSE; /// VFS will ignore ownership information on filesystem objects @@ -34,7 +32,7 @@ libc_bitflags!( MNT_NOBLOCK; /// file system is exported MNT_EXPORTED; - /// All I/O to the file system should be done asynchronously. + /// file system written asynchronously MNT_ASYNC; /// Force a read-write mount even if the file system appears to be /// unclean. @@ -53,7 +51,6 @@ libc_bitflags!( /// the specified already mounted file system. MNT_RELOAD; /// Create a snapshot of the file system. - /// MNT_SNAPSHOT; /// All I/O to the file system should be done synchronously. MNT_SYNCHRONOUS; @@ -99,12 +96,11 @@ pub fn mount< let res = source.with_nix_path(|s| target.with_nix_path(|t| { with_opt_nix_path(data, |d| unsafe { - println!("mounting {:?} to {:?}", s, t); libc::mount( s.as_ptr(), t.as_ptr(), flags.bits(), - d as *mut libc::c_void, + d.cast_mut() as *mut libc::c_void, ) }) }))???; @@ -113,11 +109,11 @@ pub fn mount< } /// Umount the file system mounted at `target`. -pub fn umount

(mountpoint: &P, flags: MntFlags) -> Result<()> +pub fn unmount

(target: &P, flags: MntFlags) -> Result<()> where P: ?Sized + NixPath, { - let res = mountpoint.with_nix_path(|cstr| unsafe { + let res = target.with_nix_path(|cstr| unsafe { libc::unmount(cstr.as_ptr(), flags.bits()) })?; diff --git a/src/mount/mod.rs b/src/mount/mod.rs index 7213447677..81e56d022a 100644 --- a/src/mount/mod.rs +++ b/src/mount/mod.rs @@ -5,7 +5,7 @@ mod linux; #[cfg(linux_android)] pub use self::linux::*; -#[cfg(bsd_without_macos)] +#[cfg(bsd_without_apple)] mod bsd; #[cfg(bsd_without_macos)] From ba11a9264497db8073affd85cd5afd74e8cc69ba Mon Sep 17 00:00:00 2001 From: owl Date: Tue, 2 Apr 2024 12:03:58 +0800 Subject: [PATCH 06/12] feat: fix code --- build.rs | 2 +- test/mount/mod.rs | 6 ++++++ test/{ => mount}/test_mount.rs | 0 test/mount/test_mount_apple.rs | 12 ++++++++++++ test/{ => mount}/test_nmount.rs | 0 test/test.rs | 5 +---- 6 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 test/mount/mod.rs rename test/{ => mount}/test_mount.rs (100%) create mode 100644 test/mount/test_mount_apple.rs rename test/{ => mount}/test_nmount.rs (100%) diff --git a/build.rs b/build.rs index 34953cc661..fd19de0fe9 100644 --- a/build.rs +++ b/build.rs @@ -19,7 +19,7 @@ fn main() { // cfg aliases we would like to use apple_targets: { any(ios, macos, watchos, tvos) }, bsd: { any(freebsd, dragonfly, netbsd, openbsd, apple_targets) }, - bsd_without_macos: { any(freebsd, dragonfly, netbsd, openbsd) }, + bsd_without_apple: { any(freebsd, dragonfly, netbsd, openbsd) }, linux_android: { any(android, linux) }, freebsdlike: { any(dragonfly, freebsd) }, netbsdlike: { any(netbsd, openbsd) }, diff --git a/test/mount/mod.rs b/test/mount/mod.rs new file mode 100644 index 0000000000..2764b83f71 --- /dev/null +++ b/test/mount/mod.rs @@ -0,0 +1,6 @@ +#[cfg(target_os = "linux")] +mod test_mount; +#[cfg(apple_targets)] +mod test_mount_apple; +#[cfg(target_os = "freebsd")] +mod test_nmount; diff --git a/test/test_mount.rs b/test/mount/test_mount.rs similarity index 100% rename from test/test_mount.rs rename to test/mount/test_mount.rs diff --git a/test/mount/test_mount_apple.rs b/test/mount/test_mount_apple.rs new file mode 100644 index 0000000000..3c53d86c14 --- /dev/null +++ b/test/mount/test_mount_apple.rs @@ -0,0 +1,12 @@ + + +use nix::errno::Errno; +use nix::mount::{mount, MntFlags}; + +use crate::*; + +#[test] +fn test_mount() { + let res = mount::("", "", MntFlags::empty(), None); + assert_eq!(res, Err(Errno::ENOENT)); +} diff --git a/test/test_nmount.rs b/test/mount/test_nmount.rs similarity index 100% rename from test/test_nmount.rs rename to test/mount/test_nmount.rs diff --git a/test/test.rs b/test/test.rs index c7231426c2..f32a85a3b7 100644 --- a/test/test.rs +++ b/test/test.rs @@ -4,6 +4,7 @@ extern crate cfg_if; extern crate nix; mod common; +mod mount; mod sys; #[cfg(not(target_os = "redox"))] mod test_dir; @@ -11,8 +12,6 @@ mod test_errno; mod test_fcntl; #[cfg(linux_android)] mod test_kmod; -#[cfg(target_os = "linux")] -mod test_mount; #[cfg(any( freebsdlike, target_os = "fushsia", @@ -23,8 +22,6 @@ mod test_mq; #[cfg(not(target_os = "redox"))] mod test_net; mod test_nix_path; -#[cfg(target_os = "freebsd")] -mod test_nmount; mod test_poll; #[cfg(not(any( target_os = "redox", From 3a6fa9b82f3bd35a11184ed23cbb06bf163814f1 Mon Sep 17 00:00:00 2001 From: owl Date: Tue, 2 Apr 2024 12:06:09 +0800 Subject: [PATCH 07/12] feat: fix code --- changelog/2347.added.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/2347.added.md diff --git a/changelog/2347.added.md b/changelog/2347.added.md new file mode 100644 index 0000000000..9000d61deb --- /dev/null +++ b/changelog/2347.added.md @@ -0,0 +1 @@ +Add `mount` and `unmount` API for apple targets. From fd4cc3627d15ea7daca8171a3531814dd3e77d8b Mon Sep 17 00:00:00 2001 From: owl Date: Tue, 2 Apr 2024 12:07:09 +0800 Subject: [PATCH 08/12] feat: fix code --- src/mount/bsd.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/mount/bsd.rs b/src/mount/bsd.rs index 248e0ab1d2..ae9eed7c0e 100644 --- a/src/mount/bsd.rs +++ b/src/mount/bsd.rs @@ -30,7 +30,7 @@ libc_bitflags!( #[cfg(target_os = "freebsd")] MNT_GJOURNAL; /// MAC support for objects. - #[cfg(any(apple_targets, target_os = "freebsd"))] + #[cfg(target_os = "freebsd")] MNT_MULTILABEL; /// Disable read clustering. #[cfg(freebsdlike)] @@ -58,7 +58,7 @@ libc_bitflags!( /// Create a snapshot of the file system. /// /// See [mksnap_ffs(8)](https://www.freebsd.org/cgi/man.cgi?query=mksnap_ffs) - #[cfg(any(apple_targets, target_os = "freebsd"))] + #[cfg(target_os = "freebsd")] MNT_SNAPSHOT; /// Using soft updates. #[cfg(any(freebsdlike, netbsdlike))] @@ -71,7 +71,6 @@ libc_bitflags!( MNT_SYNCHRONOUS; /// Union with underlying fs. #[cfg(any( - apple_targets, target_os = "freebsd", target_os = "netbsd" ))] From 9d4043b11b458b840d16e1d0b4aa763acfbf2203 Mon Sep 17 00:00:00 2001 From: owl Date: Tue, 2 Apr 2024 12:13:07 +0800 Subject: [PATCH 09/12] feat: fix code --- test/mount/test_mount_apple.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/mount/test_mount_apple.rs b/test/mount/test_mount_apple.rs index 3c53d86c14..34b5a14c13 100644 --- a/test/mount/test_mount_apple.rs +++ b/test/mount/test_mount_apple.rs @@ -1,5 +1,3 @@ - - use nix::errno::Errno; use nix::mount::{mount, MntFlags}; From 47e45ee1ed44df72e92545ad4fbacc835ed0116a Mon Sep 17 00:00:00 2001 From: owl Date: Tue, 2 Apr 2024 13:04:18 +0800 Subject: [PATCH 10/12] feat: fix code --- src/mount/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mount/mod.rs b/src/mount/mod.rs index 81e56d022a..25990e7882 100644 --- a/src/mount/mod.rs +++ b/src/mount/mod.rs @@ -8,11 +8,11 @@ pub use self::linux::*; #[cfg(bsd_without_apple)] mod bsd; -#[cfg(bsd_without_macos)] +#[cfg(bsd_without_apple)] pub use self::bsd::*; #[cfg(apple_targets)] mod apple; #[cfg(apple_targets)] -pub use self::apple::*; \ No newline at end of file +pub use self::apple::*; From 51b5910da5d0e133f441c35902474f6e4a72235b Mon Sep 17 00:00:00 2001 From: owl Date: Tue, 2 Apr 2024 14:54:48 +0800 Subject: [PATCH 11/12] feat: fix code --- src/mount/apple.rs | 11 +- src/mount/bsd_without_apple.rs | 429 +++++++++++++++++++++++++++++++++ src/mount/mod.rs | 4 +- test/mount/test_mount_apple.rs | 2 - 4 files changed, 437 insertions(+), 9 deletions(-) create mode 100644 src/mount/bsd_without_apple.rs diff --git a/src/mount/apple.rs b/src/mount/apple.rs index 9f9fccf2bf..6759ed20bb 100644 --- a/src/mount/apple.rs +++ b/src/mount/apple.rs @@ -24,9 +24,9 @@ libc_bitflags!( MNT_AUTOMOUNTED; /// filesystem is journaled MNT_JOURNALED; - /// Don't allow user extended attributes + /// Don't allow user extended attributes MNT_NOUSERXATTR; - /// filesystem should defer writes + /// filesystem should defer writes MNT_DEFWRITE; /// don't block unmount if not responding MNT_NOBLOCK; @@ -93,17 +93,18 @@ pub fn mount< } } - let res = source.with_nix_path(|s| + let res = source.with_nix_path(|s| { target.with_nix_path(|t| { with_opt_nix_path(data, |d| unsafe { libc::mount( s.as_ptr(), t.as_ptr(), flags.bits(), - d.cast_mut() as *mut libc::c_void, + d.cast_mut().cast(), ) }) - }))???; + }) + })???; Errno::result(res).map(drop) } diff --git a/src/mount/bsd_without_apple.rs b/src/mount/bsd_without_apple.rs new file mode 100644 index 0000000000..ae9eed7c0e --- /dev/null +++ b/src/mount/bsd_without_apple.rs @@ -0,0 +1,429 @@ +#[cfg(target_os = "freebsd")] +use crate::Error; +use crate::{Errno, NixPath, Result}; +use libc::c_int; +#[cfg(target_os = "freebsd")] +use libc::{c_char, c_uint, c_void}; +#[cfg(target_os = "freebsd")] +use std::{ + borrow::Cow, + ffi::{CStr, CString}, + fmt, io, + marker::PhantomData, +}; + +libc_bitflags!( + /// Used with [`Nmount::nmount`]. + pub struct MntFlags: c_int { + /// ACL support enabled. + #[cfg(any(target_os = "netbsd", target_os = "freebsd"))] + MNT_ACLS; + /// All I/O to the file system should be done asynchronously. + MNT_ASYNC; + /// dir should instead be a file system ID encoded as “FSID:val0:val1”. + #[cfg(target_os = "freebsd")] + MNT_BYFSID; + /// Force a read-write mount even if the file system appears to be + /// unclean. + MNT_FORCE; + /// GEOM journal support enabled. + #[cfg(target_os = "freebsd")] + MNT_GJOURNAL; + /// MAC support for objects. + #[cfg(target_os = "freebsd")] + MNT_MULTILABEL; + /// Disable read clustering. + #[cfg(freebsdlike)] + MNT_NOCLUSTERR; + /// Disable write clustering. + #[cfg(freebsdlike)] + MNT_NOCLUSTERW; + /// Enable NFS version 4 ACLs. + #[cfg(target_os = "freebsd")] + MNT_NFS4ACLS; + /// Do not update access times. + MNT_NOATIME; + /// Disallow program execution. + MNT_NOEXEC; + /// Do not honor setuid or setgid bits on files when executing them. + MNT_NOSUID; + /// Do not follow symlinks. + #[cfg(freebsdlike)] + MNT_NOSYMFOLLOW; + /// Mount read-only. + MNT_RDONLY; + /// Causes the vfs subsystem to update its data structures pertaining to + /// the specified already mounted file system. + MNT_RELOAD; + /// Create a snapshot of the file system. + /// + /// See [mksnap_ffs(8)](https://www.freebsd.org/cgi/man.cgi?query=mksnap_ffs) + #[cfg(target_os = "freebsd")] + MNT_SNAPSHOT; + /// Using soft updates. + #[cfg(any(freebsdlike, netbsdlike))] + MNT_SOFTDEP; + /// Directories with the SUID bit set chown new files to their own + /// owner. + #[cfg(freebsdlike)] + MNT_SUIDDIR; + /// All I/O to the file system should be done synchronously. + MNT_SYNCHRONOUS; + /// Union with underlying fs. + #[cfg(any( + target_os = "freebsd", + target_os = "netbsd" + ))] + MNT_UNION; + /// Indicates that the mount command is being applied to an already + /// mounted file system. + MNT_UPDATE; + /// Check vnode use counts. + #[cfg(target_os = "freebsd")] + MNT_NONBUSY; + } +); + +/// The Error type of [`Nmount::nmount`]. +/// +/// It wraps an [`Errno`], but also may contain an additional message returned +/// by `nmount(2)`. +#[cfg(target_os = "freebsd")] +#[derive(Debug)] +pub struct NmountError { + errno: Error, + errmsg: Option, +} + +#[cfg(target_os = "freebsd")] +impl NmountError { + /// Returns the additional error string sometimes generated by `nmount(2)`. + pub fn errmsg(&self) -> Option<&str> { + self.errmsg.as_deref() + } + + /// Returns the inner [`Error`] + pub const fn error(&self) -> Error { + self.errno + } + + fn new(error: Error, errmsg: Option<&CStr>) -> Self { + Self { + errno: error, + errmsg: errmsg.map(CStr::to_string_lossy).map(Cow::into_owned), + } + } +} + +#[cfg(target_os = "freebsd")] +impl std::error::Error for NmountError {} + +#[cfg(target_os = "freebsd")] +impl fmt::Display for NmountError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(errmsg) = &self.errmsg { + write!(f, "{:?}: {}: {}", self.errno, errmsg, self.errno.desc()) + } else { + write!(f, "{:?}: {}", self.errno, self.errno.desc()) + } + } +} + +#[cfg(target_os = "freebsd")] +impl From for io::Error { + fn from(err: NmountError) -> Self { + err.errno.into() + } +} + +/// Result type of [`Nmount::nmount`]. +#[cfg(target_os = "freebsd")] +pub type NmountResult = std::result::Result<(), NmountError>; + +/// Mount a FreeBSD file system. +/// +/// The `nmount(2)` system call works similarly to the `mount(8)` program; it +/// takes its options as a series of name-value pairs. Most of the values are +/// strings, as are all of the names. The `Nmount` structure builds up an +/// argument list and then executes the syscall. +/// +/// # Examples +/// +/// To mount `target` onto `mountpoint` with `nullfs`: +/// ``` +/// # use nix::unistd::Uid; +/// # use ::sysctl::{CtlValue, Sysctl}; +/// # let ctl = ::sysctl::Ctl::new("vfs.usermount").unwrap(); +/// # if !Uid::current().is_root() && CtlValue::Int(0) == ctl.value().unwrap() { +/// # return; +/// # }; +/// use nix::mount::{MntFlags, Nmount, unmount}; +/// use std::ffi::CString; +/// use tempfile::tempdir; +/// +/// let mountpoint = tempdir().unwrap(); +/// let target = tempdir().unwrap(); +/// +/// let fstype = CString::new("fstype").unwrap(); +/// let nullfs = CString::new("nullfs").unwrap(); +/// Nmount::new() +/// .str_opt(&fstype, &nullfs) +/// .str_opt_owned("fspath", mountpoint.path().to_str().unwrap()) +/// .str_opt_owned("target", target.path().to_str().unwrap()) +/// .nmount(MntFlags::empty()).unwrap(); +/// +/// unmount(mountpoint.path(), MntFlags::empty()).unwrap(); +/// ``` +/// +/// # See Also +/// * [`nmount(2)`](https://www.freebsd.org/cgi/man.cgi?query=nmount) +/// * [`nullfs(5)`](https://www.freebsd.org/cgi/man.cgi?query=nullfs) +#[cfg(target_os = "freebsd")] +#[derive(Debug, Default)] +pub struct Nmount<'a> { + // n.b. notgull: In reality, this is a list that contains + // both mutable and immutable pointers. + // Be careful using this. + iov: Vec, + is_owned: Vec, + marker: PhantomData<&'a ()>, +} + +#[cfg(target_os = "freebsd")] +impl<'a> Nmount<'a> { + /// Helper function to push a slice onto the `iov` array. + fn push_slice(&mut self, val: &'a [u8], is_owned: bool) { + self.iov.push(libc::iovec { + iov_base: val.as_ptr().cast_mut().cast(), + iov_len: val.len(), + }); + self.is_owned.push(is_owned); + } + + /// Helper function to push a pointer and its length onto the `iov` array. + fn push_pointer_and_length( + &mut self, + val: *const u8, + len: usize, + is_owned: bool, + ) { + self.iov.push(libc::iovec { + iov_base: val as *mut _, + iov_len: len, + }); + self.is_owned.push(is_owned); + } + + /// Helper function to push a `nix` path as owned. + fn push_nix_path(&mut self, val: &P) { + val.with_nix_path(|s| { + let len = s.to_bytes_with_nul().len(); + let ptr = s.to_owned().into_raw() as *const u8; + + self.push_pointer_and_length(ptr, len, true); + }) + .unwrap(); + } + + /// Add an opaque mount option. + /// + /// Some file systems take binary-valued mount options. They can be set + /// with this method. + /// + /// # Safety + /// + /// Unsafe because it will cause `Nmount::nmount` to dereference a raw + /// pointer. The user is responsible for ensuring that `val` is valid and + /// its lifetime outlives `self`! An easy way to do that is to give the + /// value a larger scope than `name` + /// + /// # Examples + /// ``` + /// use libc::c_void; + /// use nix::mount::Nmount; + /// use std::ffi::CString; + /// use std::mem; + /// + /// // Note that flags outlives name + /// let mut flags: u32 = 0xdeadbeef; + /// let name = CString::new("flags").unwrap(); + /// let p = &mut flags as *mut u32 as *mut c_void; + /// let len = mem::size_of_val(&flags); + /// let mut nmount = Nmount::new(); + /// unsafe { nmount.mut_ptr_opt(&name, p, len) }; + /// ``` + pub unsafe fn mut_ptr_opt( + &mut self, + name: &'a CStr, + val: *mut c_void, + len: usize, + ) -> &mut Self { + self.push_slice(name.to_bytes_with_nul(), false); + self.push_pointer_and_length(val.cast(), len, false); + self + } + + /// Add a mount option that does not take a value. + /// + /// # Examples + /// ``` + /// use nix::mount::Nmount; + /// use std::ffi::CString; + /// + /// let read_only = CString::new("ro").unwrap(); + /// Nmount::new() + /// .null_opt(&read_only); + /// ``` + pub fn null_opt(&mut self, name: &'a CStr) -> &mut Self { + self.push_slice(name.to_bytes_with_nul(), false); + self.push_slice(&[], false); + self + } + + /// Add a mount option that does not take a value, but whose name must be + /// owned. + /// + /// + /// This has higher runtime cost than [`Nmount::null_opt`], but is useful + /// when the name's lifetime doesn't outlive the `Nmount`, or it's a + /// different string type than `CStr`. + /// + /// # Examples + /// ``` + /// use nix::mount::Nmount; + /// + /// let read_only = "ro"; + /// let mut nmount: Nmount<'static> = Nmount::new(); + /// nmount.null_opt_owned(read_only); + /// ``` + pub fn null_opt_owned( + &mut self, + name: &P, + ) -> &mut Self { + self.push_nix_path(name); + self.push_slice(&[], false); + self + } + + /// Add a mount option as a [`CStr`]. + /// + /// # Examples + /// ``` + /// use nix::mount::Nmount; + /// use std::ffi::CString; + /// + /// let fstype = CString::new("fstype").unwrap(); + /// let nullfs = CString::new("nullfs").unwrap(); + /// Nmount::new() + /// .str_opt(&fstype, &nullfs); + /// ``` + pub fn str_opt(&mut self, name: &'a CStr, val: &'a CStr) -> &mut Self { + self.push_slice(name.to_bytes_with_nul(), false); + self.push_slice(val.to_bytes_with_nul(), false); + self + } + + /// Add a mount option as an owned string. + /// + /// This has higher runtime cost than [`Nmount::str_opt`], but is useful + /// when the value's lifetime doesn't outlive the `Nmount`, or it's a + /// different string type than `CStr`. + /// + /// # Examples + /// ``` + /// use nix::mount::Nmount; + /// use std::path::Path; + /// + /// let mountpoint = Path::new("/mnt"); + /// Nmount::new() + /// .str_opt_owned("fspath", mountpoint.to_str().unwrap()); + /// ``` + pub fn str_opt_owned(&mut self, name: &P1, val: &P2) -> &mut Self + where + P1: ?Sized + NixPath, + P2: ?Sized + NixPath, + { + self.push_nix_path(name); + self.push_nix_path(val); + self + } + + /// Create a new `Nmount` struct with no options + pub fn new() -> Self { + Self::default() + } + + /// Actually mount the file system. + pub fn nmount(&mut self, flags: MntFlags) -> NmountResult { + const ERRMSG_NAME: &[u8] = b"errmsg\0"; + let mut errmsg = vec![0u8; 255]; + + // nmount can return extra error information via a "errmsg" return + // argument. + self.push_slice(ERRMSG_NAME, false); + + // SAFETY: we are pushing a mutable iovec here, so we can't use + // the above method + self.iov.push(libc::iovec { + iov_base: errmsg.as_mut_ptr().cast(), + iov_len: errmsg.len(), + }); + + let niov = self.iov.len() as c_uint; + let iovp = self.iov.as_mut_ptr(); + let res = unsafe { libc::nmount(iovp, niov, flags.bits()) }; + match Errno::result(res) { + Ok(_) => Ok(()), + Err(error) => { + let errmsg = if errmsg[0] == 0 { + None + } else { + CStr::from_bytes_until_nul(&errmsg[..]).ok() + }; + Err(NmountError::new(error, errmsg)) + } + } + } +} + +#[cfg(target_os = "freebsd")] +impl<'a> Drop for Nmount<'a> { + fn drop(&mut self) { + for (iov, is_owned) in self.iov.iter().zip(self.is_owned.iter()) { + if *is_owned { + // Free the owned string. Safe because we recorded ownership, + // and Nmount does not implement Clone. + unsafe { + drop(CString::from_raw(iov.iov_base as *mut c_char)); + } + } + } + } +} + +/// Unmount the file system mounted at `mountpoint`. +/// +/// Useful flags include +/// * `MNT_FORCE` - Unmount even if still in use. +#[cfg_attr( + target_os = "freebsd", + doc = " +* `MNT_BYFSID` - `mountpoint` is not a path, but a file system ID + encoded as `FSID:val0:val1`, where `val0` and `val1` + are the contents of the `fsid_t val[]` array in decimal. + The file system that has the specified file system ID + will be unmounted. See + [`statfs`](crate::sys::statfs::statfs) to determine the + `fsid`. +" +)] +pub fn unmount

(mountpoint: &P, flags: MntFlags) -> Result<()> +where + P: ?Sized + NixPath, +{ + let res = mountpoint.with_nix_path(|cstr| unsafe { + libc::unmount(cstr.as_ptr(), flags.bits()) + })?; + + Errno::result(res).map(drop) +} diff --git a/src/mount/mod.rs b/src/mount/mod.rs index 25990e7882..41e7b3ec6d 100644 --- a/src/mount/mod.rs +++ b/src/mount/mod.rs @@ -6,10 +6,10 @@ mod linux; pub use self::linux::*; #[cfg(bsd_without_apple)] -mod bsd; +mod bsd_without_apple; #[cfg(bsd_without_apple)] -pub use self::bsd::*; +pub use self::bsd_without_apple::*; #[cfg(apple_targets)] mod apple; diff --git a/test/mount/test_mount_apple.rs b/test/mount/test_mount_apple.rs index 34b5a14c13..f2868500d0 100644 --- a/test/mount/test_mount_apple.rs +++ b/test/mount/test_mount_apple.rs @@ -1,8 +1,6 @@ use nix::errno::Errno; use nix::mount::{mount, MntFlags}; -use crate::*; - #[test] fn test_mount() { let res = mount::("", "", MntFlags::empty(), None); From a2f3797cecc87422fcacf89adaddc4a090c1fce9 Mon Sep 17 00:00:00 2001 From: owl Date: Tue, 2 Apr 2024 14:55:37 +0800 Subject: [PATCH 12/12] feat: fix code --- src/mount/bsd.rs | 429 ----------------------------------------------- 1 file changed, 429 deletions(-) delete mode 100644 src/mount/bsd.rs diff --git a/src/mount/bsd.rs b/src/mount/bsd.rs deleted file mode 100644 index ae9eed7c0e..0000000000 --- a/src/mount/bsd.rs +++ /dev/null @@ -1,429 +0,0 @@ -#[cfg(target_os = "freebsd")] -use crate::Error; -use crate::{Errno, NixPath, Result}; -use libc::c_int; -#[cfg(target_os = "freebsd")] -use libc::{c_char, c_uint, c_void}; -#[cfg(target_os = "freebsd")] -use std::{ - borrow::Cow, - ffi::{CStr, CString}, - fmt, io, - marker::PhantomData, -}; - -libc_bitflags!( - /// Used with [`Nmount::nmount`]. - pub struct MntFlags: c_int { - /// ACL support enabled. - #[cfg(any(target_os = "netbsd", target_os = "freebsd"))] - MNT_ACLS; - /// All I/O to the file system should be done asynchronously. - MNT_ASYNC; - /// dir should instead be a file system ID encoded as “FSID:val0:val1”. - #[cfg(target_os = "freebsd")] - MNT_BYFSID; - /// Force a read-write mount even if the file system appears to be - /// unclean. - MNT_FORCE; - /// GEOM journal support enabled. - #[cfg(target_os = "freebsd")] - MNT_GJOURNAL; - /// MAC support for objects. - #[cfg(target_os = "freebsd")] - MNT_MULTILABEL; - /// Disable read clustering. - #[cfg(freebsdlike)] - MNT_NOCLUSTERR; - /// Disable write clustering. - #[cfg(freebsdlike)] - MNT_NOCLUSTERW; - /// Enable NFS version 4 ACLs. - #[cfg(target_os = "freebsd")] - MNT_NFS4ACLS; - /// Do not update access times. - MNT_NOATIME; - /// Disallow program execution. - MNT_NOEXEC; - /// Do not honor setuid or setgid bits on files when executing them. - MNT_NOSUID; - /// Do not follow symlinks. - #[cfg(freebsdlike)] - MNT_NOSYMFOLLOW; - /// Mount read-only. - MNT_RDONLY; - /// Causes the vfs subsystem to update its data structures pertaining to - /// the specified already mounted file system. - MNT_RELOAD; - /// Create a snapshot of the file system. - /// - /// See [mksnap_ffs(8)](https://www.freebsd.org/cgi/man.cgi?query=mksnap_ffs) - #[cfg(target_os = "freebsd")] - MNT_SNAPSHOT; - /// Using soft updates. - #[cfg(any(freebsdlike, netbsdlike))] - MNT_SOFTDEP; - /// Directories with the SUID bit set chown new files to their own - /// owner. - #[cfg(freebsdlike)] - MNT_SUIDDIR; - /// All I/O to the file system should be done synchronously. - MNT_SYNCHRONOUS; - /// Union with underlying fs. - #[cfg(any( - target_os = "freebsd", - target_os = "netbsd" - ))] - MNT_UNION; - /// Indicates that the mount command is being applied to an already - /// mounted file system. - MNT_UPDATE; - /// Check vnode use counts. - #[cfg(target_os = "freebsd")] - MNT_NONBUSY; - } -); - -/// The Error type of [`Nmount::nmount`]. -/// -/// It wraps an [`Errno`], but also may contain an additional message returned -/// by `nmount(2)`. -#[cfg(target_os = "freebsd")] -#[derive(Debug)] -pub struct NmountError { - errno: Error, - errmsg: Option, -} - -#[cfg(target_os = "freebsd")] -impl NmountError { - /// Returns the additional error string sometimes generated by `nmount(2)`. - pub fn errmsg(&self) -> Option<&str> { - self.errmsg.as_deref() - } - - /// Returns the inner [`Error`] - pub const fn error(&self) -> Error { - self.errno - } - - fn new(error: Error, errmsg: Option<&CStr>) -> Self { - Self { - errno: error, - errmsg: errmsg.map(CStr::to_string_lossy).map(Cow::into_owned), - } - } -} - -#[cfg(target_os = "freebsd")] -impl std::error::Error for NmountError {} - -#[cfg(target_os = "freebsd")] -impl fmt::Display for NmountError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some(errmsg) = &self.errmsg { - write!(f, "{:?}: {}: {}", self.errno, errmsg, self.errno.desc()) - } else { - write!(f, "{:?}: {}", self.errno, self.errno.desc()) - } - } -} - -#[cfg(target_os = "freebsd")] -impl From for io::Error { - fn from(err: NmountError) -> Self { - err.errno.into() - } -} - -/// Result type of [`Nmount::nmount`]. -#[cfg(target_os = "freebsd")] -pub type NmountResult = std::result::Result<(), NmountError>; - -/// Mount a FreeBSD file system. -/// -/// The `nmount(2)` system call works similarly to the `mount(8)` program; it -/// takes its options as a series of name-value pairs. Most of the values are -/// strings, as are all of the names. The `Nmount` structure builds up an -/// argument list and then executes the syscall. -/// -/// # Examples -/// -/// To mount `target` onto `mountpoint` with `nullfs`: -/// ``` -/// # use nix::unistd::Uid; -/// # use ::sysctl::{CtlValue, Sysctl}; -/// # let ctl = ::sysctl::Ctl::new("vfs.usermount").unwrap(); -/// # if !Uid::current().is_root() && CtlValue::Int(0) == ctl.value().unwrap() { -/// # return; -/// # }; -/// use nix::mount::{MntFlags, Nmount, unmount}; -/// use std::ffi::CString; -/// use tempfile::tempdir; -/// -/// let mountpoint = tempdir().unwrap(); -/// let target = tempdir().unwrap(); -/// -/// let fstype = CString::new("fstype").unwrap(); -/// let nullfs = CString::new("nullfs").unwrap(); -/// Nmount::new() -/// .str_opt(&fstype, &nullfs) -/// .str_opt_owned("fspath", mountpoint.path().to_str().unwrap()) -/// .str_opt_owned("target", target.path().to_str().unwrap()) -/// .nmount(MntFlags::empty()).unwrap(); -/// -/// unmount(mountpoint.path(), MntFlags::empty()).unwrap(); -/// ``` -/// -/// # See Also -/// * [`nmount(2)`](https://www.freebsd.org/cgi/man.cgi?query=nmount) -/// * [`nullfs(5)`](https://www.freebsd.org/cgi/man.cgi?query=nullfs) -#[cfg(target_os = "freebsd")] -#[derive(Debug, Default)] -pub struct Nmount<'a> { - // n.b. notgull: In reality, this is a list that contains - // both mutable and immutable pointers. - // Be careful using this. - iov: Vec, - is_owned: Vec, - marker: PhantomData<&'a ()>, -} - -#[cfg(target_os = "freebsd")] -impl<'a> Nmount<'a> { - /// Helper function to push a slice onto the `iov` array. - fn push_slice(&mut self, val: &'a [u8], is_owned: bool) { - self.iov.push(libc::iovec { - iov_base: val.as_ptr().cast_mut().cast(), - iov_len: val.len(), - }); - self.is_owned.push(is_owned); - } - - /// Helper function to push a pointer and its length onto the `iov` array. - fn push_pointer_and_length( - &mut self, - val: *const u8, - len: usize, - is_owned: bool, - ) { - self.iov.push(libc::iovec { - iov_base: val as *mut _, - iov_len: len, - }); - self.is_owned.push(is_owned); - } - - /// Helper function to push a `nix` path as owned. - fn push_nix_path(&mut self, val: &P) { - val.with_nix_path(|s| { - let len = s.to_bytes_with_nul().len(); - let ptr = s.to_owned().into_raw() as *const u8; - - self.push_pointer_and_length(ptr, len, true); - }) - .unwrap(); - } - - /// Add an opaque mount option. - /// - /// Some file systems take binary-valued mount options. They can be set - /// with this method. - /// - /// # Safety - /// - /// Unsafe because it will cause `Nmount::nmount` to dereference a raw - /// pointer. The user is responsible for ensuring that `val` is valid and - /// its lifetime outlives `self`! An easy way to do that is to give the - /// value a larger scope than `name` - /// - /// # Examples - /// ``` - /// use libc::c_void; - /// use nix::mount::Nmount; - /// use std::ffi::CString; - /// use std::mem; - /// - /// // Note that flags outlives name - /// let mut flags: u32 = 0xdeadbeef; - /// let name = CString::new("flags").unwrap(); - /// let p = &mut flags as *mut u32 as *mut c_void; - /// let len = mem::size_of_val(&flags); - /// let mut nmount = Nmount::new(); - /// unsafe { nmount.mut_ptr_opt(&name, p, len) }; - /// ``` - pub unsafe fn mut_ptr_opt( - &mut self, - name: &'a CStr, - val: *mut c_void, - len: usize, - ) -> &mut Self { - self.push_slice(name.to_bytes_with_nul(), false); - self.push_pointer_and_length(val.cast(), len, false); - self - } - - /// Add a mount option that does not take a value. - /// - /// # Examples - /// ``` - /// use nix::mount::Nmount; - /// use std::ffi::CString; - /// - /// let read_only = CString::new("ro").unwrap(); - /// Nmount::new() - /// .null_opt(&read_only); - /// ``` - pub fn null_opt(&mut self, name: &'a CStr) -> &mut Self { - self.push_slice(name.to_bytes_with_nul(), false); - self.push_slice(&[], false); - self - } - - /// Add a mount option that does not take a value, but whose name must be - /// owned. - /// - /// - /// This has higher runtime cost than [`Nmount::null_opt`], but is useful - /// when the name's lifetime doesn't outlive the `Nmount`, or it's a - /// different string type than `CStr`. - /// - /// # Examples - /// ``` - /// use nix::mount::Nmount; - /// - /// let read_only = "ro"; - /// let mut nmount: Nmount<'static> = Nmount::new(); - /// nmount.null_opt_owned(read_only); - /// ``` - pub fn null_opt_owned( - &mut self, - name: &P, - ) -> &mut Self { - self.push_nix_path(name); - self.push_slice(&[], false); - self - } - - /// Add a mount option as a [`CStr`]. - /// - /// # Examples - /// ``` - /// use nix::mount::Nmount; - /// use std::ffi::CString; - /// - /// let fstype = CString::new("fstype").unwrap(); - /// let nullfs = CString::new("nullfs").unwrap(); - /// Nmount::new() - /// .str_opt(&fstype, &nullfs); - /// ``` - pub fn str_opt(&mut self, name: &'a CStr, val: &'a CStr) -> &mut Self { - self.push_slice(name.to_bytes_with_nul(), false); - self.push_slice(val.to_bytes_with_nul(), false); - self - } - - /// Add a mount option as an owned string. - /// - /// This has higher runtime cost than [`Nmount::str_opt`], but is useful - /// when the value's lifetime doesn't outlive the `Nmount`, or it's a - /// different string type than `CStr`. - /// - /// # Examples - /// ``` - /// use nix::mount::Nmount; - /// use std::path::Path; - /// - /// let mountpoint = Path::new("/mnt"); - /// Nmount::new() - /// .str_opt_owned("fspath", mountpoint.to_str().unwrap()); - /// ``` - pub fn str_opt_owned(&mut self, name: &P1, val: &P2) -> &mut Self - where - P1: ?Sized + NixPath, - P2: ?Sized + NixPath, - { - self.push_nix_path(name); - self.push_nix_path(val); - self - } - - /// Create a new `Nmount` struct with no options - pub fn new() -> Self { - Self::default() - } - - /// Actually mount the file system. - pub fn nmount(&mut self, flags: MntFlags) -> NmountResult { - const ERRMSG_NAME: &[u8] = b"errmsg\0"; - let mut errmsg = vec![0u8; 255]; - - // nmount can return extra error information via a "errmsg" return - // argument. - self.push_slice(ERRMSG_NAME, false); - - // SAFETY: we are pushing a mutable iovec here, so we can't use - // the above method - self.iov.push(libc::iovec { - iov_base: errmsg.as_mut_ptr().cast(), - iov_len: errmsg.len(), - }); - - let niov = self.iov.len() as c_uint; - let iovp = self.iov.as_mut_ptr(); - let res = unsafe { libc::nmount(iovp, niov, flags.bits()) }; - match Errno::result(res) { - Ok(_) => Ok(()), - Err(error) => { - let errmsg = if errmsg[0] == 0 { - None - } else { - CStr::from_bytes_until_nul(&errmsg[..]).ok() - }; - Err(NmountError::new(error, errmsg)) - } - } - } -} - -#[cfg(target_os = "freebsd")] -impl<'a> Drop for Nmount<'a> { - fn drop(&mut self) { - for (iov, is_owned) in self.iov.iter().zip(self.is_owned.iter()) { - if *is_owned { - // Free the owned string. Safe because we recorded ownership, - // and Nmount does not implement Clone. - unsafe { - drop(CString::from_raw(iov.iov_base as *mut c_char)); - } - } - } - } -} - -/// Unmount the file system mounted at `mountpoint`. -/// -/// Useful flags include -/// * `MNT_FORCE` - Unmount even if still in use. -#[cfg_attr( - target_os = "freebsd", - doc = " -* `MNT_BYFSID` - `mountpoint` is not a path, but a file system ID - encoded as `FSID:val0:val1`, where `val0` and `val1` - are the contents of the `fsid_t val[]` array in decimal. - The file system that has the specified file system ID - will be unmounted. See - [`statfs`](crate::sys::statfs::statfs) to determine the - `fsid`. -" -)] -pub fn unmount

(mountpoint: &P, flags: MntFlags) -> Result<()> -where - P: ?Sized + NixPath, -{ - let res = mountpoint.with_nix_path(|cstr| unsafe { - libc::unmount(cstr.as_ptr(), flags.bits()) - })?; - - Errno::result(res).map(drop) -}