diff --git a/CHANGELOG.md b/CHANGELOG.md index aaab7b2d75..bfb2a6ae73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,6 +56,9 @@ This project adheres to [Semantic Versioning](https://semver.org/). MacOS, FreeBSD, DragonflyBSD, Android, iOS and Haiku. ([#2074](https://github.com/nix-rust/nix/pull/2074)) +- Added `close_range(2)` on Linux + ([#2153](https://github.com/nix-rust/nix/pull/2153)) + ## [0.27.1] - 2023-08-28 ### Fixed diff --git a/src/unistd.rs b/src/unistd.rs index 700a4af3ba..25ffe71b07 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -1098,6 +1098,62 @@ pub fn close(fd: RawFd) -> Result<()> { Errno::result(res).map(drop) } +#[cfg(target_os = "linux")] +libc_bitflags! { + /// Options for close_range() + pub struct CloseRangeFlags : c_uint { + /// Unshare file descriptors before closing them. + CLOSE_RANGE_UNSHARE; + /// Set close-on-exec instead of closing file descriptors. + CLOSE_RANGE_CLOEXEC; + } +} + +/// Close a range of raw file descriptors. +/// [close_range(2)](https://man7.org/linux/man-pages/man2/close_range.2.html). +/// +/// # Safety +/// +/// Be aware that many Rust types implicitly close-on-drop, including +/// `std::fs::File`. Explicitly closing them with this method too can result in +/// a double-close condition, which can cause confusing `EBADF` errors in +/// seemingly unrelated code. Caveat programmer. +/// +/// # Examples +/// +/// ```no_run +/// use std::os::unix::io::AsRawFd; +/// use nix::unistd::{close_range, CloseRangeFlags}; +/// +/// let f = tempfile::tempfile().unwrap(); +/// unsafe { close_range(f.as_raw_fd(), f.as_raw_fd(), CloseRangeFlags::empty()).unwrap() }; // Bad! f will also close on drop! +/// ``` +/// +/// ```rust +/// use std::os::unix::io::IntoRawFd; +/// use nix::unistd::{close_range, CloseRangeFlags}; +/// +/// let f = tempfile::tempfile().unwrap(); +/// let fd = f.into_raw_fd(); // Good. into_raw_fd consumes f +/// unsafe { close_range(fd, fd, CloseRangeFlags::empty()).unwrap(); } +/// ``` +#[cfg(target_os = "linux")] +pub unsafe fn close_range( + first: RawFd, + last: RawFd, + flags: CloseRangeFlags, +) -> Result<()> { + let res = unsafe { + libc::syscall( + libc::SYS_close_range, + first as libc::c_uint, + last as libc::c_uint, + flags.bits(), + ) + }; + Errno::result(res).map(drop) +} + /// Read from a raw file descriptor. /// /// See also [read(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html)