Skip to content

Commit b7e2dc1

Browse files
committed
unistd: adding linux(glibc)/freebsd close_range.
Allows to close a range of file descriptors, can set close-on-exec on these and/or unsharing (as having its own file descriptors table after fork for the calling process).
1 parent b91bf39 commit b7e2dc1

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

src/unistd.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3992,3 +3992,49 @@ pub fn chflags<P: ?Sized + NixPath>(path: &P, flags: FileFlag) -> Result<()> {
39923992
Errno::result(res).map(drop)
39933993
}
39943994
}
3995+
3996+
#[cfg(any(
3997+
all(target_os = "linux", target_env = "gnu"),
3998+
target_os = "freebsd"
3999+
))]
4000+
#[cfg(feature = "fs")]
4001+
libc_bitflags! {
4002+
/// Options for close_range()
4003+
#[cfg_attr(docsrs, doc(cfg(feature = "fs")))]
4004+
pub struct CloseRangeFlags : c_uint {
4005+
#[cfg(all(target_os = "linux", target_env = "gnu"))]
4006+
/// Unshare the file descriptors range before closing them
4007+
CLOSE_RANGE_UNSHARE;
4008+
/// Set the close-on-exec flag on the file descriptors range
4009+
CLOSE_RANGE_CLOEXEC;
4010+
}
4011+
}
4012+
4013+
feature! {
4014+
#![feature = "fs"]
4015+
4016+
/// Close all the file descriptor from a given range.
4017+
/// An optional flag can be applied to modify its behavior.
4018+
#[cfg(any(
4019+
all(target_os = "linux", target_env = "gnu"),
4020+
target_os = "freebsd"
4021+
))]
4022+
pub fn close_range<F: std::os::fd::AsFd>(fdbegin: F, fdlast: F, flags: CloseRangeFlags) -> Result<Option<c_int>> {
4023+
use std::os::fd::AsRawFd;
4024+
4025+
let raw = unsafe {
4026+
Errno::clear();
4027+
libc::close_range(fdbegin.as_fd().as_raw_fd() as u32, fdlast.as_fd().as_raw_fd() as u32, flags.bits() as i32)
4028+
};
4029+
if raw == -1 {
4030+
if Errno::last_raw() == 0 {
4031+
Ok(None)
4032+
} else {
4033+
Err(Errno::last())
4034+
}
4035+
} else {
4036+
Ok(Some(raw))
4037+
}
4038+
4039+
}
4040+
}

test/test_unistd.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1391,3 +1391,18 @@ fn test_group_from() {
13911391
assert_eq!(group.gid, group_id);
13921392
assert_eq!(group.name, "wheel");
13931393
}
1394+
1395+
#[test]
1396+
#[cfg(any(all(target_os = "linux", target_env = "gnu"), target_os = "freebsd"))]
1397+
fn test_close_range() {
1398+
use tempfile::NamedTempFile;
1399+
const CONTENTS: &[u8] = b"abcdef123456";
1400+
let mut tempfile1 = NamedTempFile::new().unwrap();
1401+
let mut tempfile2 = NamedTempFile::new().unwrap();
1402+
let mut tempfile3 = NamedTempFile::new().unwrap();
1403+
tempfile3.write_all(CONTENTS).unwrap();
1404+
tempfile2.write_all(CONTENTS).unwrap();
1405+
tempfile1.write_all(CONTENTS).unwrap();
1406+
let areclosed = close_range(tempfile1, tempfile3, CloseRangeFlags::CLOSE_RANGE_CLOEXEC);
1407+
assert_eq!(areclosed.expect("close_range failed").expect("invalid flag"), 0);
1408+
}

0 commit comments

Comments
 (0)