summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rw-r--r--src/unistd.rs39
-rw-r--r--test/test_unistd.rs24
3 files changed, 55 insertions, 10 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 39602449..650abfb6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -47,6 +47,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
([#800](https://github.com/nix-rust/nix/pull/800))
### Changed
+- Use native `pipe2` on all BSD targets. Users should notice no difference.
+ ([#777](https://github.com/nix-rust/nix/pull/777))
- Renamed existing `ptrace` wrappers to encourage namespacing ([#692](https://github.com/nix-rust/nix/pull/692))
- Marked `sys::ptrace::ptrace` as `unsafe`.
- Changed function signature of `socket()` and `socketpair()`. The `protocol` argument
diff --git a/src/unistd.rs b/src/unistd.rs
index c3c78414..cb2a29f6 100644
--- a/src/unistd.rs
+++ b/src/unistd.rs
@@ -876,10 +876,22 @@ pub fn pipe() -> Result<(RawFd, RawFd)> {
}
}
-// libc only defines `pipe2` in `libc::notbsd`.
-#[cfg(any(target_os = "linux",
- target_os = "android",
- target_os = "emscripten"))]
+/// Like `pipe`, but allows setting certain file descriptor flags.
+///
+/// The following flags are supported, and will be set atomically as the pipe is
+/// created:
+///
+/// `O_CLOEXEC`: Set the close-on-exec flag for the new file descriptors.
+/// `O_NONBLOCK`: Set the non-blocking flag for the ends of the pipe.
+///
+/// See also [pipe(2)](http://man7.org/linux/man-pages/man2/pipe.2.html)
+#[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "emscripten",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
let mut fds: [c_int; 2] = unsafe { mem::uninitialized() };
@@ -890,9 +902,18 @@ pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
Ok((fds[0], fds[1]))
}
-#[cfg(not(any(target_os = "linux",
- target_os = "android",
- target_os = "emscripten")))]
+/// Like `pipe`, but allows setting certain file descriptor flags.
+///
+/// The following flags are supported, and will be set after the pipe is
+/// created:
+///
+/// `O_CLOEXEC`: Set the close-on-exec flag for the new file descriptors.
+/// `O_NONBLOCK`: Set the non-blocking flag for the ends of the pipe.
+#[cfg(any(target_os = "ios", target_os = "macos"))]
+#[deprecated(
+ since="0.10.0",
+ note="pipe2(2) is not actually atomic on these platforms. Use pipe(2) and fcntl(2) instead"
+)]
pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
let mut fds: [c_int; 2] = unsafe { mem::uninitialized() };
@@ -905,9 +926,7 @@ pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
Ok((fds[0], fds[1]))
}
-#[cfg(not(any(target_os = "linux",
- target_os = "android",
- target_os = "emscripten")))]
+#[cfg(any(target_os = "ios", target_os = "macos"))]
fn pipe2_setflags(fd1: RawFd, fd2: RawFd, flags: OFlag) -> Result<()> {
use fcntl::FdFlag;
use fcntl::FcntlArg::F_SETFL;
diff --git a/test/test_unistd.rs b/test/test_unistd.rs
index b29ece3e..3fe123f0 100644
--- a/test/test_unistd.rs
+++ b/test/test_unistd.rs
@@ -1,5 +1,6 @@
extern crate tempdir;
+use nix::fcntl::{fcntl, FcntlArg, FdFlag, OFlag};
use nix::unistd::*;
use nix::unistd::ForkResult::*;
use nix::sys::wait::*;
@@ -380,3 +381,26 @@ fn test_sysconf_unsupported() {
let open_max = sysconf(SysconfVar::_XOPEN_CRYPT);
assert!(open_max.expect("sysconf failed").is_none())
}
+
+// Test that we can create a pair of pipes. No need to verify that they pass
+// data; that's the domain of the OS, not nix.
+#[test]
+fn test_pipe() {
+ let (fd0, fd1) = pipe().unwrap();
+ let m0 = stat::SFlag::from_bits_truncate(stat::fstat(fd0).unwrap().st_mode);
+ // S_IFIFO means it's a pipe
+ assert_eq!(m0, SFlag::S_IFIFO);
+ let m1 = stat::SFlag::from_bits_truncate(stat::fstat(fd1).unwrap().st_mode);
+ assert_eq!(m1, SFlag::S_IFIFO);
+}
+
+// pipe2(2) is the same as pipe(2), except it allows setting some flags. Check
+// that we can set a flag.
+#[test]
+fn test_pipe2() {
+ let (fd0, fd1) = pipe2(OFlag::O_CLOEXEC).unwrap();
+ let f0 = FdFlag::from_bits_truncate(fcntl(fd0, FcntlArg::F_GETFD).unwrap());
+ assert!(f0.contains(FdFlag::FD_CLOEXEC));
+ let f1 = FdFlag::from_bits_truncate(fcntl(fd1, FcntlArg::F_GETFD).unwrap());
+ assert!(f1.contains(FdFlag::FD_CLOEXEC));
+}