diff --git a/CHANGELOG.md b/CHANGELOG.md index de01c2f7f0..43d122ab10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] - ReleaseDate ### Added +- Add `MntFlags` and `unmount` on all of the BSDs. + ([#1849](https://github.com/nix-rust/nix/pull/1849)) +- Added a 'Statfs::flags' method. + ([#1849](https://github.com/nix-rust/nix/pull/1849)) - Added `NSFS_MAGIC` FsType on Linux and Android. ([#1829](https://github.com/nix-rust/nix/pull/1829)) - Added `sched_getcpu` on platforms that support it. diff --git a/Cargo.toml b/Cargo.toml index 2edb003b41..e09f758a25 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ targets = [ ] [dependencies] -libc = { version = "0.2.135", features = [ "extra_traits" ] } +libc = { git = "https://github.com/rust-lang/libc", rev = "cc19b6f0801", features = [ "extra_traits" ] } bitflags = "1.1" cfg-if = "1.0" pin-utils = { version = "0.1.0", optional = true } diff --git a/src/lib.rs b/src/lib.rs index 770258dd36..6b82125761 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -106,7 +106,6 @@ feature! { #[allow(missing_docs)] pub mod kmod; } -#[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] feature! { #![feature = "mount"] pub mod mount; diff --git a/src/mount/bsd.rs b/src/mount/bsd.rs index 109522f9fb..1ba8b80902 100644 --- a/src/mount/bsd.rs +++ b/src/mount/bsd.rs @@ -1,16 +1,22 @@ +#[cfg(target_os = "freebsd")] use crate::{ Error, +}; +use crate::{ Errno, NixPath, Result, }; -use libc::{c_char, c_int, c_uint, c_void}; +#[cfg(target_os = "freebsd")] +use libc::{c_char, c_uint, c_void}; +use libc::c_int; +#[cfg(target_os = "freebsd")] use std::{ borrow::Cow, ffi::{CString, CStr}, + marker::PhantomData, fmt, io, - marker::PhantomData, }; @@ -110,12 +116,14 @@ libc_bitflags!( /// /// 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> { @@ -135,8 +143,10 @@ impl NmountError { } } +#[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 { @@ -147,6 +157,7 @@ impl fmt::Display for NmountError { } } +#[cfg(target_os = "freebsd")] impl From for io::Error { fn from(err: NmountError) -> Self { err.errno.into() @@ -154,6 +165,7 @@ impl From for io::Error { } /// Result type of [`Nmount::nmount`]. +#[cfg(target_os = "freebsd")] pub type NmountResult = std::result::Result<(), NmountError>; /// Mount a FreeBSD file system. @@ -425,13 +437,15 @@ impl<'a> Drop for Nmount<'a> { /// /// Useful flags include /// * `MNT_FORCE` - Unmount even if still in use. -/// * `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`. +#[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 { diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs index 04a6f937a4..af19c52dfd 100644 --- a/src/sys/socket/mod.rs +++ b/src/sys/socket/mod.rs @@ -272,14 +272,17 @@ libc_bitflags! { /// Sends or requests out-of-band data on sockets that support this notion /// (e.g., of type [`Stream`](enum.SockType.html)); the underlying protocol must also /// support out-of-band data. + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_OOB; /// Peeks at an incoming message. The data is treated as unread and the next /// [`recv()`](fn.recv.html) /// or similar function shall still return this data. + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_PEEK; /// Receive operation blocks until the full amount of data can be /// returned. The function may return smaller amount of data if a signal /// is caught, an error or disconnect occurs. + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_WAITALL; /// Enables nonblocking operation; if the operation would block, /// `EAGAIN` or `EWOULDBLOCK` is returned. This provides similar @@ -291,8 +294,10 @@ libc_bitflags! { /// which will affect all threads in /// the calling process and as well as other processes that hold /// file descriptors referring to the same open file description. + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_DONTWAIT; /// Receive flags: Control Data was discarded (buffer too small) + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_CTRUNC; /// For raw ([`Packet`](addr/enum.AddressFamily.html)), Internet datagram /// (since Linux 2.4.27/2.6.8), @@ -302,15 +307,18 @@ libc_bitflags! { /// domain ([unix(7)](https://linux.die.net/man/7/unix)) sockets. /// /// For use with Internet stream sockets, see [tcp(7)](https://linux.die.net/man/7/tcp). + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_TRUNC; /// Terminates a record (when this notion is supported, as for /// sockets of type [`SeqPacket`](enum.SockType.html)). + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_EOR; /// This flag specifies that queued errors should be received from /// the socket error queue. (For more details, see /// [recvfrom(2)](https://linux.die.net/man/2/recvfrom)) #[cfg(any(target_os = "android", target_os = "linux"))] #[cfg_attr(docsrs, doc(cfg(all())))] + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_ERRQUEUE; /// Set the `close-on-exec` flag for the file descriptor received via a UNIX domain /// file descriptor using the `SCM_RIGHTS` operation (described in @@ -326,6 +334,7 @@ libc_bitflags! { target_os = "netbsd", target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_CMSG_CLOEXEC; /// Requests not to send `SIGPIPE` errors when the other end breaks the connection. /// (For more details, see [send(2)](https://linux.die.net/man/2/send)). @@ -340,6 +349,7 @@ libc_bitflags! { target_os = "openbsd", target_os = "solaris"))] #[cfg_attr(docsrs, doc(cfg(all())))] + #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 MSG_NOSIGNAL; } } diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs index 83196dbadc..9c28bc2120 100644 --- a/src/sys/statfs.rs +++ b/src/sys/statfs.rs @@ -7,7 +7,19 @@ use std::os::unix::io::AsRawFd; #[cfg(not(any(target_os = "linux", target_os = "android")))] use std::ffi::CStr; +use cfg_if::cfg_if; + use crate::{NixPath, Result, errno::Errno}; +#[cfg(all(feature = "mount", + any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd") +))] +use crate::mount::MntFlags; +#[cfg(target_os = "linux")] +use crate::sys::statvfs::FsFlags; /// Identifies a mounted file system #[cfg(target_os = "android")] @@ -18,10 +30,30 @@ pub type fsid_t = libc::__fsid_t; #[cfg_attr(docsrs, doc(cfg(all())))] pub type fsid_t = libc::fsid_t; +cfg_if! { + if #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] { + type type_of_statfs = libc::statfs64; + const LIBC_FSTATFS: unsafe extern fn + (fd: libc::c_int, buf: *mut type_of_statfs) -> libc::c_int + = libc::fstatfs64; + const LIBC_STATFS: unsafe extern fn + (path: *const libc::c_char, buf: *mut type_of_statfs) -> libc::c_int + = libc::statfs64; + } else { + type type_of_statfs = libc::statfs; + const LIBC_FSTATFS: unsafe extern fn + (fd: libc::c_int, buf: *mut type_of_statfs) -> libc::c_int + = libc::fstatfs; + const LIBC_STATFS: unsafe extern fn + (path: *const libc::c_char, buf: *mut type_of_statfs) -> libc::c_int + = libc::statfs; + } +} + /// Describes a mounted file system #[derive(Clone, Copy)] #[repr(transparent)] -pub struct Statfs(libc::statfs); +pub struct Statfs(type_of_statfs); #[cfg(target_os = "freebsd")] type fs_type_t = u32; @@ -352,6 +384,29 @@ impl Statfs { self.0.f_bsize } + /// Get the mount flags + #[cfg(all(feature = "mount", + any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd") + ))] + #[cfg_attr(docsrs, doc(cfg(all())))] + #[allow(clippy::unnecessary_cast)] // Not unnecessary on all arches + pub fn flags(&self) -> MntFlags { + MntFlags::from_bits_truncate(self.0.f_flags as i32) + } + + /// Get the mount flags + // The f_flags field exists on Android and Fuchsia too, but without man + // pages I can't tell if it can be cast to FsFlags. + #[cfg(target_os = "linux")] + #[cfg_attr(docsrs, doc(cfg(all())))] + pub fn flags(&self) -> FsFlags { + FsFlags::from_bits_truncate(self.0.f_flags as libc::c_ulong) + } + /// Maximum length of filenames #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] #[cfg_attr(docsrs, doc(cfg(all())))] @@ -400,7 +455,9 @@ impl Statfs { target_os = "macos", target_os = "android", target_os = "freebsd", + target_os = "fuchsia", target_os = "openbsd", + target_os = "linux", ))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks(&self) -> u64 { @@ -415,24 +472,9 @@ impl Statfs { } /// Total data blocks in filesystem - #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))))] + #[cfg(target_os = "emscripten")] #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks(&self) -> u64 { - self.0.f_blocks - } - - /// Total data blocks in filesystem - #[cfg(not(any( - target_os = "ios", - target_os = "macos", - target_os = "android", - target_os = "freebsd", - target_os = "openbsd", - target_os = "dragonfly", - all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))) - )))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks(&self) -> libc::c_ulong { + pub fn blocks(&self) -> u32 { self.0.f_blocks } @@ -442,7 +484,9 @@ impl Statfs { target_os = "macos", target_os = "android", target_os = "freebsd", + target_os = "fuchsia", target_os = "openbsd", + target_os = "linux", ))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_free(&self) -> u64 { @@ -457,29 +501,20 @@ impl Statfs { } /// Free blocks in filesystem - #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))))] + #[cfg(target_os = "emscripten")] #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks_free(&self) -> u64 { + pub fn blocks_free(&self) -> u32 { self.0.f_bfree } - /// Free blocks in filesystem - #[cfg(not(any( + /// Free blocks available to unprivileged user + #[cfg(any( target_os = "ios", target_os = "macos", target_os = "android", - target_os = "freebsd", - target_os = "openbsd", - target_os = "dragonfly", - all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))) - )))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks_free(&self) -> libc::c_ulong { - self.0.f_bfree - } - - /// Free blocks available to unprivileged user - #[cfg(any(target_os = "ios", target_os = "macos", target_os = "android"))] + target_os = "fuchsia", + target_os = "linux", + ))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn blocks_available(&self) -> u64 { self.0.f_bavail @@ -500,24 +535,9 @@ impl Statfs { } /// Free blocks available to unprivileged user - #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))))] + #[cfg(target_os = "emscripten")] #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks_available(&self) -> u64 { - self.0.f_bavail - } - - /// Free blocks available to unprivileged user - #[cfg(not(any( - target_os = "ios", - target_os = "macos", - target_os = "android", - target_os = "freebsd", - target_os = "openbsd", - target_os = "dragonfly", - all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))) - )))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn blocks_available(&self) -> libc::c_ulong { + pub fn blocks_available(&self) -> u32 { self.0.f_bavail } @@ -527,7 +547,9 @@ impl Statfs { target_os = "macos", target_os = "android", target_os = "freebsd", + target_os = "fuchsia", target_os = "openbsd", + target_os = "linux", ))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files(&self) -> u64 { @@ -542,33 +564,20 @@ impl Statfs { } /// Total file nodes in filesystem - #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))))] + #[cfg(target_os = "emscripten")] #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn files(&self) -> libc::fsfilcnt_t { + pub fn files(&self) -> u32 { self.0.f_files } - /// Total file nodes in filesystem - #[cfg(not(any( + /// Free file nodes in filesystem + #[cfg(any( target_os = "ios", target_os = "macos", target_os = "android", - target_os = "freebsd", + target_os = "fuchsia", target_os = "openbsd", - target_os = "dragonfly", - all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))) - )))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn files(&self) -> libc::c_ulong { - self.0.f_files - } - - /// Free file nodes in filesystem - #[cfg(any( - target_os = "android", - target_os = "ios", - target_os = "macos", - target_os = "openbsd" + target_os = "linux", ))] #[cfg_attr(docsrs, doc(cfg(all())))] pub fn files_free(&self) -> u64 { @@ -590,24 +599,9 @@ impl Statfs { } /// Free file nodes in filesystem - #[cfg(all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))))] - #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn files_free(&self) -> libc::fsfilcnt_t { - self.0.f_ffree - } - - /// Free file nodes in filesystem - #[cfg(not(any( - target_os = "ios", - target_os = "macos", - target_os = "android", - target_os = "freebsd", - target_os = "openbsd", - target_os = "dragonfly", - all(target_os = "linux", any(target_env = "musl", target_arch = "riscv32", all(target_arch = "x86_64", target_pointer_width = "32"))) - )))] + #[cfg(target_os = "emscripten")] #[cfg_attr(docsrs, doc(cfg(all())))] - pub fn files_free(&self) -> libc::c_ulong { + pub fn files_free(&self) -> u32 { self.0.f_ffree } @@ -619,16 +613,25 @@ impl Statfs { impl Debug for Statfs { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Statfs") - .field("optimal_transfer_size", &self.optimal_transfer_size()) - .field("block_size", &self.block_size()) - .field("blocks", &self.blocks()) - .field("blocks_free", &self.blocks_free()) - .field("blocks_available", &self.blocks_available()) - .field("files", &self.files()) - .field("files_free", &self.files_free()) - .field("filesystem_id", &self.filesystem_id()) - .finish() + let mut ds = f.debug_struct("Statfs"); + ds.field("optimal_transfer_size", &self.optimal_transfer_size()); + ds.field("block_size", &self.block_size()); + ds.field("blocks", &self.blocks()); + ds.field("blocks_free", &self.blocks_free()); + ds.field("blocks_available", &self.blocks_available()); + ds.field("files", &self.files()); + ds.field("files_free", &self.files_free()); + ds.field("filesystem_id", &self.filesystem_id()); + #[cfg(all(feature = "mount", + any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd") + ))] + ds.field("flags", &self.flags()); + ds.finish() + } } @@ -642,8 +645,8 @@ impl Debug for Statfs { /// `path` - Path to any file within the file system to describe pub fn statfs(path: &P) -> Result { unsafe { - let mut stat = mem::MaybeUninit::::uninit(); - let res = path.with_nix_path(|path| libc::statfs(path.as_ptr(), stat.as_mut_ptr()))?; + let mut stat = mem::MaybeUninit::::uninit(); + let res = path.with_nix_path(|path| LIBC_STATFS(path.as_ptr(), stat.as_mut_ptr()))?; Errno::result(res).map(|_| Statfs(stat.assume_init())) } } @@ -658,8 +661,8 @@ pub fn statfs(path: &P) -> Result { /// `fd` - File descriptor of any open file within the file system to describe pub fn fstatfs(fd: &T) -> Result { unsafe { - let mut stat = mem::MaybeUninit::::uninit(); - Errno::result(libc::fstatfs(fd.as_raw_fd(), stat.as_mut_ptr())) + let mut stat = mem::MaybeUninit::::uninit(); + Errno::result(LIBC_FSTATFS(fd.as_raw_fd(), stat.as_mut_ptr())) .map(|_| Statfs(stat.assume_init())) } }