]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #27980 - tbu-:pr_cloexec_dup, r=alexcrichton
authorbors <bors@rust-lang.org>
Mon, 31 Aug 2015 07:24:39 +0000 (07:24 +0000)
committerbors <bors@rust-lang.org>
Mon, 31 Aug 2015 07:24:39 +0000 (07:24 +0000)
Still needs values of F_DUPFD_CLOEXEC on other OSs.

For Bitrig, NetBSD and OpenBSD the constant was incorrectly in posix01, when
it's actually posix08. In order to maintain backwards-compatiblity, the
constant was only copied, not moved.

cc #24237

src/liblibc/lib.rs
src/libstd/sys/unix/net.rs

index c4d2dc838942a852a7f43f2bb356bc6502bd89ca..95b5ccca75397bb7514c72a40836cc060ef4df2b 100644 (file)
@@ -3614,6 +3614,7 @@ pub mod posix01 {
         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 posix01 {
         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 posix01 {
             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 posix01 {
         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 posix01 {
         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;
index e65f64f2029801177ef8a68995a7152aecf235c6..f1a9518d08de5d2fd5743e9825a289c13111db19 100644 (file)
 use ffi::CStr;
 use io;
 use libc::{self, c_int, size_t};
+use net::SocketAddr;
 use str;
+use sync::atomic::{self, AtomicBool};
 use sys::c;
-use net::SocketAddr;
 use sys::fd::FileDesc;
 use sys_common::{AsInner, FromInner, IntoInner};
 use sys_common::net::{getsockopt, setsockopt};
@@ -66,10 +67,29 @@ pub fn accept(&self, storage: *mut libc::sockaddr,
     }
 
     pub fn duplicate(&self) -> io::Result<Socket> {
-        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<usize> {