diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index c4d2dc83894..95b5ccca753 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -3614,6 +3614,7 @@ pub mod consts { pub mod posix08 { use types::os::arch::c95::c_int; pub const O_CLOEXEC: c_int = 0x80000; + pub const F_DUPFD_CLOEXEC: c_int = 1030; } #[cfg(any(target_arch = "arm", target_arch = "aarch64", @@ -4285,11 +4286,13 @@ pub mod consts { pub mod posix08 { use types::os::arch::c95::c_int; pub const O_CLOEXEC: c_int = 0x100000; + pub const F_DUPFD_CLOEXEC: c_int = 17; } #[cfg(target_os = "dragonfly")] pub mod posix08 { use types::os::arch::c95::c_int; pub const O_CLOEXEC: c_int = 0x20000; + pub const F_DUPFD_CLOEXEC: c_int = 17; } pub mod bsd44 { use types::os::arch::c95::c_int; @@ -4657,7 +4660,6 @@ pub mod consts { pub const F_GETLK : c_int = 7; pub const F_SETLK : c_int = 8; pub const F_SETLKW : c_int = 9; - pub const F_DUPFD_CLOEXEC : c_int = 10; pub const SIGTRAP : c_int = 5; pub const SIG_IGN: size_t = 1; @@ -4739,11 +4741,13 @@ pub mod consts { pub mod posix08 { use types::os::arch::c95::c_int; pub const O_CLOEXEC: c_int = 0x10000; + pub const F_DUPFD_CLOEXEC: c_int = 10; } #[cfg(target_os = "netbsd")] pub mod posix08 { use types::os::arch::c95::c_int; pub const O_CLOEXEC: c_int = 0x400000; + pub const F_DUPFD_CLOEXEC: c_int = 12; } pub mod bsd44 { use types::os::arch::c95::c_int; @@ -5186,6 +5190,7 @@ pub mod consts { pub mod posix08 { use types::os::arch::c95::c_int; pub const O_CLOEXEC: c_int = 0x1000000; + pub const F_DUPFD_CLOEXEC: c_int = 67; } pub mod bsd44 { use types::os::arch::c95::c_int; diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index e65f64f2029..f1a9518d08d 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -13,9 +13,10 @@ use prelude::v1::*; use ffi::CStr; use io; use libc::{self, c_int, size_t}; -use str; -use sys::c; use net::SocketAddr; +use str; +use sync::atomic::{self, AtomicBool}; +use sys::c; use sys::fd::FileDesc; use sys_common::{AsInner, FromInner, IntoInner}; use sys_common::net::{getsockopt, setsockopt}; @@ -66,10 +67,29 @@ impl Socket { } pub fn duplicate(&self) -> io::Result { - let fd = try!(cvt(unsafe { libc::dup(self.0.raw()) })); - let fd = FileDesc::new(fd); - fd.set_cloexec(); - Ok(Socket(fd)) + use libc::funcs::posix88::fcntl::fcntl; + let make_socket = |fd| { + let fd = FileDesc::new(fd); + fd.set_cloexec(); + Socket(fd) + }; + static EMULATE_F_DUPFD_CLOEXEC: AtomicBool = AtomicBool::new(false); + if !EMULATE_F_DUPFD_CLOEXEC.load(atomic::Ordering::Relaxed) { + match cvt(unsafe { fcntl(self.0.raw(), libc::F_DUPFD_CLOEXEC, 0) }) { + // `EINVAL` can only be returned on two occasions: Invalid + // command (second parameter) or invalid third parameter. 0 is + // always a valid third parameter, so it must be the second + // parameter. + // + // Store the result in a global variable so we don't try each + // syscall twice. + Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => { + EMULATE_F_DUPFD_CLOEXEC.store(true, atomic::Ordering::Relaxed); + } + res => return res.map(make_socket), + } + } + cvt(unsafe { fcntl(self.0.raw(), libc::F_DUPFD, 0) }).map(make_socket) } pub fn read(&self, buf: &mut [u8]) -> io::Result {