From 709cbdf12cacb6ecf42cca9000d1d46380b6ba62 Mon Sep 17 00:00:00 2001 From: Michael Neumann Date: Fri, 17 Nov 2017 12:23:41 +0100 Subject: [PATCH] Fix support for DragonFly * DragonFly does not have a O_DSYNC flag * Fix type_of_cmsg_data on DragonFly * No fexecve() on DragonFly * Do not run aio test cases on DragonFly * Keep target lists in alphabetical order * Unscrable #[cfg] directives and use cfg_if! macro instead * Fix errno on DragonFly Below follows an explanation why we have to use a C extension to get errno working on DragonFly: DragonFly uses a thread-local errno variable, but #[thread_local] is feature-gated and not available in stable Rust as of this writing (Rust 1.21.0). We have to use a C extension (src/errno_dragonfly.c) to access it. Tracking issue for `thread_local` stabilization: https://github.com/rust-lang/rust/issues/29594 Once this becomes stable, we can remove build.rs, src/errno_dragonfly.c, remove the build-dependency from Cargo.toml, and use: extern { #[thread_local] static errno: c_int; } Now all targets will use the build.rs script, but only on DragonFly this will do something. Also, there are no additional dependencies for targets other than DragonFly (no gcc dep). --- Cargo.toml | 3 +++ build.rs | 12 +++++++++++ src/errno.rs | 26 +++++++++++++++++------ src/errno_dragonfly.c | 3 +++ src/fcntl.rs | 1 - src/sys/socket/ffi.rs | 48 +++++++++++++++++++++---------------------- src/unistd.rs | 7 +++++-- test/sys/mod.rs | 16 ++++++++++++--- test/test_unistd.rs | 13 ++++++------ 9 files changed, 87 insertions(+), 42 deletions(-) create mode 100644 build.rs create mode 100644 src/errno_dragonfly.c diff --git a/Cargo.toml b/Cargo.toml index f9e375455e..6eff225ed0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,9 @@ bitflags = "1.0" cfg-if = "0.1.0" void = "1.0.2" +[target.'cfg(target_os = "dragonfly")'.build-dependencies] +gcc = "0.3" + [dev-dependencies] lazy_static = "1" rand = "0.3.8" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000000..d6a9a5031c --- /dev/null +++ b/build.rs @@ -0,0 +1,12 @@ +#[cfg(target_os = "dragonfly")] +extern crate gcc; + +#[cfg(target_os = "dragonfly")] +fn main() { + gcc::Build::new() + .file("src/errno_dragonfly.c") + .compile("liberrno_dragonfly.a"); +} + +#[cfg(not(target_os = "dragonfly"))] +fn main() {} diff --git a/src/errno.rs b/src/errno.rs index cbbf83806f..70da6c919e 100644 --- a/src/errno.rs +++ b/src/errno.rs @@ -1,4 +1,6 @@ -use libc::{self, c_int}; +#[cfg(not(target_os = "dragonfly"))] +use libc; +use libc::c_int; use std::{fmt, io, error}; use {Error, Result}; @@ -12,11 +14,23 @@ cfg_if! { libc::__error() } } else if #[cfg(target_os = "dragonfly")] { - unsafe fn errno_location() -> *mut c_int { - // FIXME: Replace with errno-dragonfly crate as this is no longer the correct - // implementation. - extern { fn __dfly_error() -> *mut c_int; } - __dfly_error() + // DragonFly uses a thread-local errno variable, but #[thread_local] is + // feature-gated and not available in stable Rust as of this writing + // (Rust 1.21.0). We have to use a C extension to access it + // (src/errno_dragonfly.c). + // + // Tracking issue for `thread_local` stabilization: + // + // https://github.com/rust-lang/rust/issues/29594 + // + // Once this becomes stable, we can remove build.rs, + // src/errno_dragonfly.c, and use: + // + // extern { #[thread_local] static errno: c_int; } + // + #[link(name="errno_dragonfly", kind="static")] + extern { + pub fn errno_location() -> *mut c_int; } } else if #[cfg(any(target_os = "android", target_os = "netbsd", diff --git a/src/errno_dragonfly.c b/src/errno_dragonfly.c new file mode 100644 index 0000000000..32fb4dab4d --- /dev/null +++ b/src/errno_dragonfly.c @@ -0,0 +1,3 @@ +#include + +int *errno_location() { return &errno; } diff --git a/src/fcntl.rs b/src/fcntl.rs index 86375e4adb..5abf65ac72 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -48,7 +48,6 @@ libc_bitflags!( O_DIRECTORY; /// Implicitly follow each `write()` with an `fdatasync()`. #[cfg(any(target_os = "android", - target_os = "dragonfly", target_os = "ios", target_os = "linux", target_os = "macos", diff --git a/src/sys/socket/ffi.rs b/src/sys/socket/ffi.rs index 265a97c976..d91b130eec 100644 --- a/src/sys/socket/ffi.rs +++ b/src/sys/socket/ffi.rs @@ -5,32 +5,32 @@ pub use libc::{socket, listen, bind, accept, connect, setsockopt, sendto, recvfr use libc::{c_int, c_void, socklen_t, ssize_t}; -#[cfg(not(target_os = "macos"))] -use libc::size_t; - -#[cfg(not(target_os = "linux"))] -use libc::c_uint; - use sys::uio::IoVec; -#[cfg(target_os = "linux")] -pub type type_of_cmsg_len = size_t; - -#[cfg(not(target_os = "linux"))] -pub type type_of_cmsg_len = socklen_t; - -// OSX always aligns struct cmsghdr as if it were a 32-bit OS -#[cfg(target_os = "macos")] -pub type type_of_cmsg_data = c_uint; - -#[cfg(not(target_os = "macos"))] -pub type type_of_cmsg_data = size_t; - -#[cfg(target_os = "linux")] -pub type type_of_msg_iovlen = size_t; - -#[cfg(not(target_os = "linux"))] -pub type type_of_msg_iovlen = c_uint; +cfg_if! { + if #[cfg(target_os = "dragonfly")] { + use libc::c_uint; + pub type type_of_cmsg_len = socklen_t; + pub type type_of_cmsg_data = c_int; + pub type type_of_msg_iovlen = c_uint; + } else if #[cfg(target_os = "linux")] { + use libc::size_t; + pub type type_of_cmsg_len = size_t; + pub type type_of_cmsg_data = size_t; + pub type type_of_msg_iovlen = size_t; + } else if #[cfg(target_os = "macos")] { + use libc::c_uint; + pub type type_of_cmsg_len = socklen_t; + // OSX always aligns struct cmsghdr as if it were a 32-bit OS + pub type type_of_cmsg_data = c_uint; + pub type type_of_msg_iovlen = c_uint; + } else { + use libc::{c_uint, size_t}; + pub type type_of_cmsg_len = socklen_t; + pub type type_of_cmsg_data = size_t; + pub type type_of_msg_iovlen = c_uint; + } +} // Private because we don't expose any external functions that operate // directly on this type; we just use it internally at FFI boundaries. diff --git a/src/unistd.rs b/src/unistd.rs index c3c78414ae..81333b748e 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -630,8 +630,11 @@ pub fn execvp(filename: &CString, args: &[CString]) -> Result { /// /// This function is similar to `execve`, except that the program to be executed /// is referenced as a file descriptor instead of a path. -#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", - target_os = "netbsd", target_os = "openbsd", target_os = "linux"))] +#[cfg(any(target_os = "android", + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_os = "openbsd"))] #[inline] pub fn fexecve(fd: RawFd, args: &[CString], env: &[CString]) -> Result { let args_p = to_exec_array(args); diff --git a/test/sys/mod.rs b/test/sys/mod.rs index 3aab9fc5b2..31cf73b1d9 100644 --- a/test/sys/mod.rs +++ b/test/sys/mod.rs @@ -1,6 +1,15 @@ mod test_signal; -#[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios", - target_os = "netbsd", target_os = "macos", target_os = "linux"))] + +// NOTE: DragonFly lacks a kernel-level implementation of Posix AIO as of +// this writing. There is an user-level implementation, but whether aio +// works or not heavily depends on which pthread implementation is chosen +// by the user at link time. For this reason we do not want to run aio test +// cases on DragonFly. +#[cfg(any(target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd"))] mod test_aio; #[cfg(target_os = "linux")] mod test_signalfd; @@ -14,5 +23,6 @@ mod test_uio; #[cfg(target_os = "linux")] mod test_epoll; mod test_pthread; -#[cfg(any(target_os = "linux", target_os = "android"))] +#[cfg(any(target_os = "android", + target_os = "linux"))] mod test_ptrace; diff --git a/test/test_unistd.rs b/test/test_unistd.rs index b29ece3e37..11e57ff719 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -241,16 +241,17 @@ cfg_if!{ if #[cfg(target_os = "android")] { execve_test_factory!(test_execve, execve, &CString::new("/system/bin/sh").unwrap()); execve_test_factory!(test_fexecve, fexecve, File::open("/system/bin/sh").unwrap().into_raw_fd()); - } else if #[cfg(any(target_os = "dragonfly", - target_os = "freebsd", + } else if #[cfg(any(target_os = "freebsd", + target_os = "linux", target_os = "netbsd", - target_os = "openbsd", - target_os = "linux", ))] { + target_os = "openbsd"))] { execve_test_factory!(test_execve, execve, &CString::new("/bin/sh").unwrap()); execve_test_factory!(test_fexecve, fexecve, File::open("/bin/sh").unwrap().into_raw_fd()); - } else if #[cfg(any(target_os = "ios", target_os = "macos", ))] { + } else if #[cfg(any(target_os = "dragonfly", + target_os = "ios", + target_os = "macos"))] { execve_test_factory!(test_execve, execve, &CString::new("/bin/sh").unwrap()); - // No fexecve() on macos/ios. + // No fexecve() on macos/ios and DragonFly. } }