Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for OpenBSD #688

Merged
merged 5 commits into from
Aug 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).
It accepts a `None` value for default protocol that was specified with zero using `c_int`.
([#647](https://github.com/nix-rust/nix/pull/647))

# Fixed
- Fix compilation and tests for OpenBSD targets
([#688](https://github.com/nix-rust/nix/pull/688))

## [0.9.0] 2017-07-23

### Added
Expand Down
25 changes: 25 additions & 0 deletions nix-test/src/const.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,31 @@ get_int_const(const char* err) {
GET_CONST(ECANCELED);
#endif

#if defined(__OpenBSD__)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can revert the changes to this file. This file has been obsolete ever since most constants moved into libc. libc has its own, superior version.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added these to get the errno tests passing. It looks like the check_errno macro uses them via assert_const_eq or did I miss something?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Grr, I thought we had already removed that. Go ahead and leave these changes in for now; we'll delete them in a future PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we do conversions of our code to use upstream libc values, we can remove these tests incrementally until they're all gone. But for now, we should add these tests if we have any hard-coded values (like all the errno values currently are).

GET_CONST(EAUTH);
GET_CONST(EBADRPC);
GET_CONST(ECANCELED);
GET_CONST(EDQUOT);
GET_CONST(EFTYPE);
GET_CONST(EILSEQ);
GET_CONST(EIPSEC);
GET_CONST(EMEDIUMTYPE);
GET_CONST(ENEEDAUTH);
GET_CONST(ENOATTR);
GET_CONST(ENOMEDIUM);
GET_CONST(ENOTSUP);
GET_CONST(EOPNOTSUPP);
GET_CONST(EOVERFLOW);
GET_CONST(EPROCLIM);
GET_CONST(EPROCUNAVAIL);
GET_CONST(EPROGMISMATCH);
GET_CONST(EPROGUNAVAIL);
GET_CONST(EREMOTE);
GET_CONST(ERPCMISMATCH);
GET_CONST(ESTALE);
GET_CONST(EUSERS);
#endif

#ifdef DARWIN
GET_CONST(EPWROFF);
GET_CONST(EDEVERR);
Expand Down
38 changes: 24 additions & 14 deletions src/sys/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,16 @@ pub struct KEvent {
kevent: libc::kevent,
}

#[cfg(any(target_os = "openbsd", target_os = "freebsd",
target_os = "dragonfly", target_os = "macos",
target_os = "ios"))]
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
target_os = "ios", target_os = "macos",
target_os = "openbsd"))]
type type_of_udata = *mut libc::c_void;
#[cfg(any(target_os = "openbsd", target_os = "freebsd",
target_os = "dragonfly", target_os = "macos",
target_os = "ios"))]
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
target_os = "ios", target_os = "macos"))]
type type_of_data = libc::intptr_t;
#[cfg(any(target_os = "netbsd"))]
type type_of_udata = intptr_t;
#[cfg(any(target_os = "netbsd"))]
#[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
type type_of_data = libc::int64_t;

#[cfg(not(target_os = "netbsd"))]
Expand Down Expand Up @@ -78,17 +77,26 @@ pub enum EventFilter {
EVFILT_TIMER = libc::EVFILT_TIMER,
}

#[cfg(any(target_os = "macos", target_os = "ios",
target_os = "freebsd", target_os = "dragonfly"))]
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
target_os = "ios", target_os = "macos",
target_os = "openbsd"))]
pub type type_of_event_flag = u16;
#[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
#[cfg(any(target_os = "netbsd"))]
pub type type_of_event_flag = u32;
libc_bitflags!{
pub flags EventFlag: type_of_event_flag {
EV_ADD,
EV_CLEAR,
EV_DELETE,
EV_DISABLE,
// No released version of OpenBSD supports EV_DISPATCH or EV_RECEIPT.
// These have been commited to the -current branch though and are
// expected to be part of the OpenBSD 6.2 release in Nov 2017.
// See: https://marc.info/?l=openbsd-tech&m=149621427511219&w=2
// https://github.com/rust-lang/libc/pull/613
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
target_os = "ios", target_os = "macos",
target_os = "netbsd"))]
EV_DISPATCH,
#[cfg(target_os = "freebsd")]
EV_DROP,
Expand All @@ -105,7 +113,9 @@ libc_bitflags!{
EV_OOBAND,
#[cfg(any(target_os = "macos", target_os = "ios"))]
EV_POLL,
#[cfg(not(target_os = "openbsd"))]
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
target_os = "ios", target_os = "macos",
target_os = "netbsd"))]
EV_RECEIPT,
EV_SYSFLAGS,
}
Expand Down Expand Up @@ -315,21 +325,21 @@ fn test_struct_kevent() {

let expected = libc::kevent{ident: 0xdeadbeef,
filter: libc::EVFILT_READ,
flags: libc::EV_DISPATCH | libc::EV_ADD,
flags: libc::EV_ONESHOT | libc::EV_ADD,
fflags: libc::NOTE_CHILD | libc::NOTE_EXIT,
data: 0x1337,
udata: udata as type_of_udata};
let actual = KEvent::new(0xdeadbeef,
EventFilter::EVFILT_READ,
EV_DISPATCH | EV_ADD,
EV_ONESHOT | EV_ADD,
NOTE_CHILD | NOTE_EXIT,
0x1337,
udata);
assert!(expected.ident == actual.ident());
assert!(expected.filter == actual.filter() as type_of_event_filter);
assert!(expected.flags == actual.flags().bits());
assert!(expected.fflags == actual.fflags().bits());
assert!(expected.data == actual.data());
assert!(expected.data == actual.data() as type_of_data);
assert!(expected.udata == actual.udata() as type_of_udata);
assert!(mem::size_of::<libc::kevent>() == mem::size_of::<KEvent>());
}
193 changes: 103 additions & 90 deletions src/sys/signal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@

use libc;
use {Errno, Error, Result};
use std::fmt;
use std::fmt::Debug;
use std::mem;
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
use std::os::unix::io::RawFd;
use std::ptr;

#[cfg(not(target_os = "openbsd"))]
pub use self::sigevent::*;

// Currently there is only one definition of c_int in libc, as well as only one
// type for signal constants.
// We would prefer to use the libc::c_int alias in the repr attribute. Unfortunately
Expand Down Expand Up @@ -488,102 +489,114 @@ pub enum SigevNotify {
si_value: libc::intptr_t },
}

/// Used to request asynchronous notification of the completion of certain
/// events, such as POSIX AIO and timers.
#[repr(C)]
pub struct SigEvent {
sigevent: libc::sigevent
}
#[cfg(not(target_os = "openbsd"))]
mod sigevent {
use libc;
use std::mem;
use std::ptr;
use std::fmt::{self, Debug};
use super::SigevNotify;
#[cfg(any(target_os = "freebsd", target_os = "linux"))]
use super::type_of_thread_id;

/// Used to request asynchronous notification of the completion of certain
/// events, such as POSIX AIO and timers.
#[repr(C)]
pub struct SigEvent {
sigevent: libc::sigevent
}

impl SigEvent {
/// **Note:** this constructor does not allow the user to set the
/// `sigev_notify_kevent_flags` field. That's considered ok because on FreeBSD
/// at least those flags don't do anything useful. That field is part of a
/// union that shares space with the more genuinely useful fields.
///
/// **Note:** This constructor also doesn't allow the caller to set the
/// `sigev_notify_function` or `sigev_notify_attributes` fields, which are
/// required for `SIGEV_THREAD`. That's considered ok because on no operating
/// system is `SIGEV_THREAD` the most efficient way to deliver AIO
/// notification. FreeBSD and DragonFly BSD programs should prefer `SIGEV_KEVENT`.
/// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or
/// `SIGEV_SIGNAL`. That field is part of a union that shares space with the
/// more genuinely useful `sigev_notify_thread_id`
pub fn new(sigev_notify: SigevNotify) -> SigEvent {
let mut sev = unsafe { mem::zeroed::<libc::sigevent>()};
sev.sigev_notify = match sigev_notify {
SigevNotify::SigevNone => libc::SIGEV_NONE,
SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL,
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
SigevNotify::SigevKevent{..} => libc::SIGEV_KEVENT,
#[cfg(target_os = "freebsd")]
SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
#[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))]
SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
#[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))]
SigevNotify::SigevThreadId{..} => 4 // No SIGEV_THREAD_ID defined
};
sev.sigev_signo = match sigev_notify {
SigevNotify::SigevSignal{ signal, .. } => signal as libc::c_int,
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
SigevNotify::SigevKevent{ kq, ..} => kq,
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
SigevNotify::SigevThreadId{ signal, .. } => signal as libc::c_int,
_ => 0
};
sev.sigev_value.sival_ptr = match sigev_notify {
SigevNotify::SigevNone => ptr::null_mut::<libc::c_void>(),
SigevNotify::SigevSignal{ si_value, .. } => si_value as *mut libc::c_void,
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
SigevNotify::SigevKevent{ udata, .. } => udata as *mut libc::c_void,
#[cfg(any(target_os = "freebsd", target_os = "linux"))]
SigevNotify::SigevThreadId{ si_value, .. } => si_value as *mut libc::c_void,
};
SigEvent::set_tid(&mut sev, &sigev_notify);
SigEvent{sigevent: sev}
}

impl SigEvent {
// Note: this constructor does not allow the user to set the
// sigev_notify_kevent_flags field. That's considered ok because on FreeBSD
// at least those flags don't do anything useful. That field is part of a
// union that shares space with the more genuinely useful
// Note: This constructor also doesn't allow the caller to set the
// sigev_notify_function or sigev_notify_attributes fields, which are
// required for SIGEV_THREAD. That's considered ok because on no operating
// system is SIGEV_THREAD the most efficient way to deliver AIO
// notification. FreeBSD and Dragonfly programs should prefer SIGEV_KEVENT.
// Linux, Solaris, and portable programs should prefer SIGEV_THREAD_ID or
// SIGEV_SIGNAL. That field is part of a union that shares space with the
// more genuinely useful sigev_notify_thread_id
pub fn new(sigev_notify: SigevNotify) -> SigEvent {
let mut sev = unsafe { mem::zeroed::<libc::sigevent>()};
sev.sigev_notify = match sigev_notify {
SigevNotify::SigevNone => libc::SIGEV_NONE,
SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL,
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
SigevNotify::SigevKevent{..} => libc::SIGEV_KEVENT,
#[cfg(target_os = "freebsd")]
SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
#[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))]
SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
#[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))]
SigevNotify::SigevThreadId{..} => 4 // No SIGEV_THREAD_ID defined
};
sev.sigev_signo = match sigev_notify {
SigevNotify::SigevSignal{ signal, .. } => signal as libc::c_int,
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
SigevNotify::SigevKevent{ kq, ..} => kq,
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
SigevNotify::SigevThreadId{ signal, .. } => signal as libc::c_int,
_ => 0
};
sev.sigev_value.sival_ptr = match sigev_notify {
SigevNotify::SigevNone => ptr::null_mut::<libc::c_void>(),
SigevNotify::SigevSignal{ si_value, .. } => si_value as *mut libc::c_void,
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
SigevNotify::SigevKevent{ udata, .. } => udata as *mut libc::c_void,
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
SigevNotify::SigevThreadId{ si_value, .. } => si_value as *mut libc::c_void,
};
SigEvent::set_tid(&mut sev, &sigev_notify);
SigEvent{sigevent: sev}
}
#[cfg(any(target_os = "freebsd", target_os = "linux"))]
fn set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify) {
sev.sigev_notify_thread_id = match sigev_notify {
&SigevNotify::SigevThreadId { thread_id, .. } => thread_id,
_ => 0 as type_of_thread_id
};
}

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
fn set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify) {
sev.sigev_notify_thread_id = match sigev_notify {
&SigevNotify::SigevThreadId { thread_id, .. } => thread_id,
_ => 0 as type_of_thread_id
};
}
#[cfg(not(any(target_os = "freebsd", target_os = "linux")))]
fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) {
}

#[cfg(not(any(target_os = "freebsd", target_os = "linux")))]
fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) {
pub fn sigevent(&self) -> libc::sigevent {
self.sigevent
}
}

pub fn sigevent(&self) -> libc::sigevent {
self.sigevent
}
}
impl Debug for SigEvent {
#[cfg(any(target_os = "freebsd", target_os = "linux"))]
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("SigEvent")
.field("sigev_notify", &self.sigevent.sigev_notify)
.field("sigev_signo", &self.sigevent.sigev_signo)
.field("sigev_value", &self.sigevent.sigev_value.sival_ptr)
.field("sigev_notify_thread_id",
&self.sigevent.sigev_notify_thread_id)
.finish()
}

impl Debug for SigEvent {
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("SigEvent")
.field("sigev_notify", &self.sigevent.sigev_notify)
.field("sigev_signo", &self.sigevent.sigev_signo)
.field("sigev_value", &self.sigevent.sigev_value.sival_ptr)
.field("sigev_notify_thread_id",
&self.sigevent.sigev_notify_thread_id)
.finish()
}

#[cfg(not(any(target_os = "linux", target_os = "freebsd")))]
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("SigEvent")
.field("sigev_notify", &self.sigevent.sigev_notify)
.field("sigev_signo", &self.sigevent.sigev_signo)
.field("sigev_value", &self.sigevent.sigev_value.sival_ptr)
.finish()
#[cfg(not(any(target_os = "freebsd", target_os = "linux")))]
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("SigEvent")
.field("sigev_notify", &self.sigevent.sigev_notify)
.field("sigev_signo", &self.sigevent.sigev_signo)
.field("sigev_value", &self.sigevent.sigev_value.sival_ptr)
.finish()
}
}
}

impl<'a> From<&'a libc::sigevent> for SigEvent {
fn from(sigevent: &libc::sigevent) -> Self {
SigEvent{ sigevent: sigevent.clone() }
impl<'a> From<&'a libc::sigevent> for SigEvent {
fn from(sigevent: &libc::sigevent) -> Self {
SigEvent{ sigevent: sigevent.clone() }
}
}
}

Expand Down
19 changes: 15 additions & 4 deletions src/sys/socket/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@

pub use libc::{socket, listen, bind, accept, connect, setsockopt, sendto, recvfrom, getsockname, getpeername, recv, send};

use libc::{c_int, c_void, socklen_t, size_t, ssize_t};
use libc::{c_int, c_void, socklen_t, ssize_t};

#[cfg(target_os = "macos")]
#[cfg(not(target_os = "macos"))]
use libc::size_t;

#[cfg(not(target_os = "linux"))]
use libc::c_uint;

use sys::uio::IoVec;
Expand All @@ -23,19 +26,27 @@ 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;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should only be one empty line following this.

// Private because we don't expose any external functions that operate
// directly on this type; we just use it internally at FFI boundaries.
// Note that in some cases we store pointers in *const fields that the
// kernel will proceed to mutate, so users should be careful about the
// actual mutability of data pointed to by this structure.
//
// FIXME: Replace these structs with the ones defined in libc
#[repr(C)]
pub struct msghdr<'a> {
pub msg_name: *const c_void,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This struct should be replaced with the FFI types declared in libc, but that doesn't need to be done for this PR. Please add a FIXME stating that.

pub msg_namelen: socklen_t,
pub msg_iov: *const IoVec<&'a [u8]>,
pub msg_iovlen: size_t,
pub msg_iovlen: type_of_msg_iovlen,
pub msg_control: *const c_void,
pub msg_controllen: size_t,
pub msg_controllen: type_of_cmsg_len,
pub msg_flags: c_int,
}

Expand Down
Loading