summaryrefslogtreecommitdiffstats
path: root/third_party/rust/nix/src/sys
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/nix/src/sys
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/nix/src/sys')
-rw-r--r--third_party/rust/nix/src/sys/aio.rs1286
-rw-r--r--third_party/rust/nix/src/sys/epoll.rs110
-rw-r--r--third_party/rust/nix/src/sys/event.rs352
-rw-r--r--third_party/rust/nix/src/sys/eventfd.rs18
-rw-r--r--third_party/rust/nix/src/sys/ioctl/bsd.rs102
-rw-r--r--third_party/rust/nix/src/sys/ioctl/linux.rs140
-rw-r--r--third_party/rust/nix/src/sys/ioctl/mod.rs778
-rw-r--r--third_party/rust/nix/src/sys/memfd.rs20
-rw-r--r--third_party/rust/nix/src/sys/mman.rs296
-rw-r--r--third_party/rust/nix/src/sys/mod.rs90
-rw-r--r--third_party/rust/nix/src/sys/pthread.rs13
-rw-r--r--third_party/rust/nix/src/sys/ptrace/bsd.rs170
-rw-r--r--third_party/rust/nix/src/sys/ptrace/linux.rs402
-rw-r--r--third_party/rust/nix/src/sys/ptrace/mod.rs22
-rw-r--r--third_party/rust/nix/src/sys/quota.rs274
-rw-r--r--third_party/rust/nix/src/sys/reboot.rs45
-rw-r--r--third_party/rust/nix/src/sys/select.rs335
-rw-r--r--third_party/rust/nix/src/sys/sendfile.rs200
-rw-r--r--third_party/rust/nix/src/sys/signal.rs984
-rw-r--r--third_party/rust/nix/src/sys/signalfd.rs170
-rw-r--r--third_party/rust/nix/src/sys/socket/addr.rs1408
-rw-r--r--third_party/rust/nix/src/sys/socket/mod.rs1204
-rw-r--r--third_party/rust/nix/src/sys/socket/sockopt.rs631
-rw-r--r--third_party/rust/nix/src/sys/stat.rs286
-rw-r--r--third_party/rust/nix/src/sys/statfs.rs20
-rw-r--r--third_party/rust/nix/src/sys/statvfs.rs161
-rw-r--r--third_party/rust/nix/src/sys/sysinfo.rs73
-rw-r--r--third_party/rust/nix/src/sys/termios.rs1108
-rw-r--r--third_party/rust/nix/src/sys/time.rs573
-rw-r--r--third_party/rust/nix/src/sys/uio.rs195
-rw-r--r--third_party/rust/nix/src/sys/utsname.rs68
-rw-r--r--third_party/rust/nix/src/sys/wait.rs239
32 files changed, 11773 insertions, 0 deletions
diff --git a/third_party/rust/nix/src/sys/aio.rs b/third_party/rust/nix/src/sys/aio.rs
new file mode 100644
index 0000000000..c54c2e316e
--- /dev/null
+++ b/third_party/rust/nix/src/sys/aio.rs
@@ -0,0 +1,1286 @@
+// vim: tw=80
+//! POSIX Asynchronous I/O
+//!
+//! The POSIX AIO interface is used for asynchronous I/O on files and disk-like
+//! devices. It supports [`read`](struct.AioCb.html#method.read),
+//! [`write`](struct.AioCb.html#method.write), and
+//! [`fsync`](struct.AioCb.html#method.fsync) operations. Completion
+//! notifications can optionally be delivered via
+//! [signals](../signal/enum.SigevNotify.html#variant.SigevSignal), via the
+//! [`aio_suspend`](fn.aio_suspend.html) function, or via polling. Some
+//! platforms support other completion
+//! notifications, such as
+//! [kevent](../signal/enum.SigevNotify.html#variant.SigevKevent).
+//!
+//! Multiple operations may be submitted in a batch with
+//! [`lio_listio`](fn.lio_listio.html), though the standard does not guarantee
+//! that they will be executed atomically.
+//!
+//! Outstanding operations may be cancelled with
+//! [`cancel`](struct.AioCb.html#method.cancel) or
+//! [`aio_cancel_all`](fn.aio_cancel_all.html), though the operating system may
+//! not support this for all filesystems and devices.
+
+use {Error, Result};
+use errno::Errno;
+use std::os::unix::io::RawFd;
+use libc::{c_void, off_t, size_t};
+use libc;
+use std::borrow::{Borrow, BorrowMut};
+use std::fmt;
+use std::fmt::Debug;
+use std::marker::PhantomData;
+use std::mem;
+use std::ptr::{null, null_mut};
+use sys::signal::*;
+use std::thread;
+use sys::time::TimeSpec;
+
+libc_enum! {
+ /// Mode for `AioCb::fsync`. Controls whether only data or both data and
+ /// metadata are synced.
+ #[repr(i32)]
+ pub enum AioFsyncMode {
+ /// do it like `fsync`
+ O_SYNC,
+ /// on supported operating systems only, do it like `fdatasync`
+ #[cfg(any(target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ O_DSYNC
+ }
+}
+
+libc_enum! {
+ /// When used with [`lio_listio`](fn.lio_listio.html), determines whether a
+ /// given `aiocb` should be used for a read operation, a write operation, or
+ /// ignored. Has no effect for any other aio functions.
+ #[repr(i32)]
+ pub enum LioOpcode {
+ LIO_NOP,
+ LIO_WRITE,
+ LIO_READ,
+ }
+}
+
+libc_enum! {
+ /// Mode for [`lio_listio`](fn.lio_listio.html)
+ #[repr(i32)]
+ pub enum LioMode {
+ /// Requests that [`lio_listio`](fn.lio_listio.html) block until all
+ /// requested operations have been completed
+ LIO_WAIT,
+ /// Requests that [`lio_listio`](fn.lio_listio.html) return immediately
+ LIO_NOWAIT,
+ }
+}
+
+/// Return values for [`AioCb::cancel`](struct.AioCb.html#method.cancel) and
+/// [`aio_cancel_all`](fn.aio_cancel_all.html)
+#[repr(i32)]
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum AioCancelStat {
+ /// All outstanding requests were canceled
+ AioCanceled = libc::AIO_CANCELED,
+ /// Some requests were not canceled. Their status should be checked with
+ /// `AioCb::error`
+ AioNotCanceled = libc::AIO_NOTCANCELED,
+ /// All of the requests have already finished
+ AioAllDone = libc::AIO_ALLDONE,
+}
+
+/// Owns (uniquely or shared) a memory buffer to keep it from `Drop`ing while
+/// the kernel has a pointer to it.
+pub enum Buffer<'a> {
+ /// No buffer to own.
+ ///
+ /// Used for operations like `aio_fsync` that have no data, or for unsafe
+ /// operations that work with raw pointers.
+ None,
+ /// Keeps a reference to a slice
+ Phantom(PhantomData<&'a mut [u8]>),
+ /// Generic thing that keeps a buffer from dropping
+ BoxedSlice(Box<Borrow<[u8]>>),
+ /// Generic thing that keeps a mutable buffer from dropping
+ BoxedMutSlice(Box<BorrowMut<[u8]>>),
+}
+
+impl<'a> Debug for Buffer<'a> {
+ // Note: someday it may be possible to Derive Debug for a trait object, but
+ // not today.
+ // https://github.com/rust-lang/rust/issues/1563
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ Buffer::None => write!(fmt, "None"),
+ Buffer::Phantom(p) => p.fmt(fmt),
+ Buffer::BoxedSlice(ref bs) => {
+ let borrowed : &Borrow<[u8]> = bs.borrow();
+ write!(fmt, "BoxedSlice({:?})",
+ borrowed as *const Borrow<[u8]>)
+ },
+ Buffer::BoxedMutSlice(ref bms) => {
+ let borrowed : &BorrowMut<[u8]> = bms.borrow();
+ write!(fmt, "BoxedMutSlice({:?})",
+ borrowed as *const BorrowMut<[u8]>)
+ }
+ }
+ }
+}
+
+/// AIO Control Block.
+///
+/// The basic structure used by all aio functions. Each `AioCb` represents one
+/// I/O request.
+pub struct AioCb<'a> {
+ aiocb: libc::aiocb,
+ /// Tracks whether the buffer pointed to by `libc::aiocb.aio_buf` is mutable
+ mutable: bool,
+ /// Could this `AioCb` potentially have any in-kernel state?
+ in_progress: bool,
+ /// Optionally keeps a reference to the data.
+ ///
+ /// Used to keep buffers from `Drop`'ing, and may be returned once the
+ /// `AioCb` is completed by [`buffer`](#method.buffer).
+ buffer: Buffer<'a>
+}
+
+impl<'a> AioCb<'a> {
+ /// Remove the inner `Buffer` and return it
+ ///
+ /// It is an error to call this method while the `AioCb` is still in
+ /// progress.
+ pub fn buffer(&mut self) -> Buffer<'a> {
+ assert!(!self.in_progress);
+ let mut x = Buffer::None;
+ mem::swap(&mut self.buffer, &mut x);
+ x
+ }
+
+ /// Remove the inner boxed slice, if any, and return it.
+ ///
+ /// The returned value will be the argument that was passed to
+ /// `from_boxed_slice` when this `AioCb` was created.
+ ///
+ /// It is an error to call this method while the `AioCb` is still in
+ /// progress.
+ pub fn boxed_slice(&mut self) -> Option<Box<Borrow<[u8]>>> {
+ assert!(!self.in_progress, "Can't remove the buffer from an AioCb that's still in-progress. Did you forget to call aio_return?");
+ if let Buffer::BoxedSlice(_) = self.buffer {
+ let mut oldbuffer = Buffer::None;
+ mem::swap(&mut self.buffer, &mut oldbuffer);
+ if let Buffer::BoxedSlice(inner) = oldbuffer {
+ Some(inner)
+ } else {
+ unreachable!();
+ }
+ } else {
+ None
+ }
+ }
+
+ /// Remove the inner boxed mutable slice, if any, and return it.
+ ///
+ /// The returned value will be the argument that was passed to
+ /// `from_boxed_mut_slice` when this `AioCb` was created.
+ ///
+ /// It is an error to call this method while the `AioCb` is still in
+ /// progress.
+ pub fn boxed_mut_slice(&mut self) -> Option<Box<BorrowMut<[u8]>>> {
+ assert!(!self.in_progress, "Can't remove the buffer from an AioCb that's still in-progress. Did you forget to call aio_return?");
+ if let Buffer::BoxedMutSlice(_) = self.buffer {
+ let mut oldbuffer = Buffer::None;
+ mem::swap(&mut self.buffer, &mut oldbuffer);
+ if let Buffer::BoxedMutSlice(inner) = oldbuffer {
+ Some(inner)
+ } else {
+ unreachable!();
+ }
+ } else {
+ None
+ }
+ }
+
+ /// Returns the underlying file descriptor associated with the `AioCb`
+ pub fn fd(&self) -> RawFd {
+ self.aiocb.aio_fildes
+ }
+
+ /// Constructs a new `AioCb` with no associated buffer.
+ ///
+ /// The resulting `AioCb` structure is suitable for use with `AioCb::fsync`.
+ ///
+ /// # Parameters
+ ///
+ /// * `fd`: File descriptor. Required for all aio functions.
+ /// * `prio`: If POSIX Prioritized IO is supported, then the
+ /// operation will be prioritized at the process's
+ /// priority level minus `prio`.
+ /// * `sigev_notify`: Determines how you will be notified of event
+ /// completion.
+ ///
+ /// # Examples
+ ///
+ /// Create an `AioCb` from a raw file descriptor and use it for an
+ /// [`fsync`](#method.fsync) operation.
+ ///
+ /// ```
+ /// # extern crate tempfile;
+ /// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify::SigevNone;
+ /// # use std::{thread, time};
+ /// # use std::os::unix::io::AsRawFd;
+ /// # use tempfile::tempfile;
+ /// # fn main() {
+ /// let f = tempfile().unwrap();
+ /// let mut aiocb = AioCb::from_fd( f.as_raw_fd(), 0, SigevNone);
+ /// aiocb.fsync(AioFsyncMode::O_SYNC).expect("aio_fsync failed early");
+ /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
+ /// thread::sleep(time::Duration::from_millis(10));
+ /// }
+ /// aiocb.aio_return().expect("aio_fsync failed late");
+ /// # }
+ /// ```
+ pub fn from_fd(fd: RawFd, prio: libc::c_int,
+ sigev_notify: SigevNotify) -> AioCb<'a> {
+ let mut a = AioCb::common_init(fd, prio, sigev_notify);
+ a.aio_offset = 0;
+ a.aio_nbytes = 0;
+ a.aio_buf = null_mut();
+
+ AioCb {
+ aiocb: a,
+ mutable: false,
+ in_progress: false,
+ buffer: Buffer::None
+ }
+ }
+
+ /// Constructs a new `AioCb` from a mutable slice.
+ ///
+ /// The resulting `AioCb` will be suitable for both read and write
+ /// operations, but only if the borrow checker can guarantee that the slice
+ /// will outlive the `AioCb`. That will usually be the case if the `AioCb`
+ /// is stack-allocated. If the borrow checker gives you trouble, try using
+ /// [`from_boxed_mut_slice`](#method.from_boxed_mut_slice) instead.
+ ///
+ /// # Parameters
+ ///
+ /// * `fd`: File descriptor. Required for all aio functions.
+ /// * `offs`: File offset
+ /// * `buf`: A memory buffer
+ /// * `prio`: If POSIX Prioritized IO is supported, then the
+ /// operation will be prioritized at the process's
+ /// priority level minus `prio`
+ /// * `sigev_notify`: Determines how you will be notified of event
+ /// completion.
+ /// * `opcode`: This field is only used for `lio_listio`. It
+ /// determines which operation to use for this individual
+ /// aiocb
+ ///
+ /// # Examples
+ ///
+ /// Create an `AioCb` from a mutable slice and read into it.
+ ///
+ /// ```
+ /// # extern crate tempfile;
+ /// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify;
+ /// # use std::{thread, time};
+ /// # use std::io::Write;
+ /// # use std::os::unix::io::AsRawFd;
+ /// # use tempfile::tempfile;
+ /// # fn main() {
+ /// const INITIAL: &[u8] = b"abcdef123456";
+ /// const LEN: usize = 4;
+ /// let mut rbuf = vec![0; LEN];
+ /// let mut f = tempfile().unwrap();
+ /// f.write_all(INITIAL).unwrap();
+ /// {
+ /// let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(),
+ /// 2, //offset
+ /// &mut rbuf,
+ /// 0, //priority
+ /// SigevNotify::SigevNone,
+ /// LioOpcode::LIO_NOP);
+ /// aiocb.read().unwrap();
+ /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
+ /// thread::sleep(time::Duration::from_millis(10));
+ /// }
+ /// assert_eq!(aiocb.aio_return().unwrap() as usize, LEN);
+ /// }
+ /// assert_eq!(rbuf, b"cdef");
+ /// # }
+ /// ```
+ pub fn from_mut_slice(fd: RawFd, offs: off_t, buf: &'a mut [u8],
+ prio: libc::c_int, sigev_notify: SigevNotify,
+ opcode: LioOpcode) -> AioCb<'a> {
+ let mut a = AioCb::common_init(fd, prio, sigev_notify);
+ a.aio_offset = offs;
+ a.aio_nbytes = buf.len() as size_t;
+ a.aio_buf = buf.as_ptr() as *mut c_void;
+ a.aio_lio_opcode = opcode as libc::c_int;
+
+ AioCb {
+ aiocb: a,
+ mutable: true,
+ in_progress: false,
+ buffer: Buffer::Phantom(PhantomData),
+ }
+ }
+
+ /// The safest and most flexible way to create an `AioCb`.
+ ///
+ /// Unlike [`from_slice`], this method returns a structure suitable for
+ /// placement on the heap. It may be used for write operations, but not
+ /// read operations. Unlike `from_ptr`, this method will ensure that the
+ /// buffer doesn't `drop` while the kernel is still processing it. Any
+ /// object that can be borrowed as a boxed slice will work.
+ ///
+ /// # Parameters
+ ///
+ /// * `fd`: File descriptor. Required for all aio functions.
+ /// * `offs`: File offset
+ /// * `buf`: A boxed slice-like object
+ /// * `prio`: If POSIX Prioritized IO is supported, then the
+ /// operation will be prioritized at the process's
+ /// priority level minus `prio`
+ /// * `sigev_notify`: Determines how you will be notified of event
+ /// completion.
+ /// * `opcode`: This field is only used for `lio_listio`. It
+ /// determines which operation to use for this individual
+ /// aiocb
+ ///
+ /// # Examples
+ ///
+ /// Create an `AioCb` from a Vector and use it for writing
+ ///
+ /// ```
+ /// # extern crate tempfile;
+ /// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify;
+ /// # use std::{thread, time};
+ /// # use std::io::Write;
+ /// # use std::os::unix::io::AsRawFd;
+ /// # use tempfile::tempfile;
+ /// # fn main() {
+ /// let wbuf = Box::new(Vec::from("CDEF"));
+ /// let expected_len = wbuf.len();
+ /// let mut f = tempfile().unwrap();
+ /// let mut aiocb = AioCb::from_boxed_slice( f.as_raw_fd(),
+ /// 2, //offset
+ /// wbuf,
+ /// 0, //priority
+ /// SigevNotify::SigevNone,
+ /// LioOpcode::LIO_NOP);
+ /// aiocb.write().unwrap();
+ /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
+ /// thread::sleep(time::Duration::from_millis(10));
+ /// }
+ /// assert_eq!(aiocb.aio_return().unwrap() as usize, expected_len);
+ /// # }
+ /// ```
+ ///
+ /// Create an `AioCb` from a `Bytes` object
+ ///
+ /// ```
+ /// # extern crate bytes;
+ /// # extern crate tempfile;
+ /// # extern crate nix;
+ /// # use bytes::Bytes;
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify;
+ /// # use std::os::unix::io::AsRawFd;
+ /// # use tempfile::tempfile;
+ /// # fn main() {
+ /// let wbuf = Box::new(Bytes::from(&b"CDEF"[..]));
+ /// let mut f = tempfile().unwrap();
+ /// let mut aiocb = AioCb::from_boxed_slice( f.as_raw_fd(),
+ /// 2, //offset
+ /// wbuf,
+ /// 0, //priority
+ /// SigevNotify::SigevNone,
+ /// LioOpcode::LIO_NOP);
+ /// # }
+ /// ```
+ ///
+ /// If a library needs to work with buffers that aren't `Box`ed, it can
+ /// create a `Box`ed container for use with this method. Here's an example
+ /// using an un`Box`ed `Bytes` object.
+ ///
+ /// ```
+ /// # extern crate bytes;
+ /// # extern crate tempfile;
+ /// # extern crate nix;
+ /// # use bytes::Bytes;
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify;
+ /// # use std::borrow::Borrow;
+ /// # use std::os::unix::io::AsRawFd;
+ /// # use tempfile::tempfile;
+ /// struct BytesContainer(Bytes);
+ /// impl Borrow<[u8]> for BytesContainer {
+ /// fn borrow(&self) -> &[u8] {
+ /// self.0.as_ref()
+ /// }
+ /// }
+ /// fn main() {
+ /// let wbuf = Bytes::from(&b"CDEF"[..]);
+ /// let boxed_wbuf = Box::new(BytesContainer(wbuf));
+ /// let mut f = tempfile().unwrap();
+ /// let mut aiocb = AioCb::from_boxed_slice( f.as_raw_fd(),
+ /// 2, //offset
+ /// boxed_wbuf,
+ /// 0, //priority
+ /// SigevNotify::SigevNone,
+ /// LioOpcode::LIO_NOP);
+ /// }
+ /// ```
+ ///
+ /// [`from_slice`]: #method.from_slice
+ pub fn from_boxed_slice(fd: RawFd, offs: off_t, buf: Box<Borrow<[u8]>>,
+ prio: libc::c_int, sigev_notify: SigevNotify,
+ opcode: LioOpcode) -> AioCb<'a> {
+ let mut a = AioCb::common_init(fd, prio, sigev_notify);
+ {
+ let borrowed : &Borrow<[u8]> = buf.borrow();
+ let slice : &[u8] = borrowed.borrow();
+ a.aio_nbytes = slice.len() as size_t;
+ a.aio_buf = slice.as_ptr() as *mut c_void;
+ }
+ a.aio_offset = offs;
+ a.aio_lio_opcode = opcode as libc::c_int;
+
+ AioCb {
+ aiocb: a,
+ mutable: false,
+ in_progress: false,
+ buffer: Buffer::BoxedSlice(buf),
+ }
+ }
+
+ /// The safest and most flexible way to create an `AioCb` for reading.
+ ///
+ /// Like [`from_boxed_slice`], but the slice is a mutable one. More
+ /// flexible than [`from_mut_slice`], because a wide range of objects can be
+ /// used.
+ ///
+ /// # Examples
+ ///
+ /// Create an `AioCb` from a Vector and use it for reading
+ ///
+ /// ```
+ /// # extern crate tempfile;
+ /// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify;
+ /// # use std::{thread, time};
+ /// # use std::io::Write;
+ /// # use std::os::unix::io::AsRawFd;
+ /// # use tempfile::tempfile;
+ /// # fn main() {
+ /// const INITIAL: &[u8] = b"abcdef123456";
+ /// const LEN: usize = 4;
+ /// let rbuf = Box::new(vec![0; LEN]);
+ /// let mut f = tempfile().unwrap();
+ /// f.write_all(INITIAL).unwrap();
+ /// let mut aiocb = AioCb::from_boxed_mut_slice( f.as_raw_fd(),
+ /// 2, //offset
+ /// rbuf,
+ /// 0, //priority
+ /// SigevNotify::SigevNone,
+ /// LioOpcode::LIO_NOP);
+ /// aiocb.read().unwrap();
+ /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
+ /// thread::sleep(time::Duration::from_millis(10));
+ /// }
+ /// assert_eq!(aiocb.aio_return().unwrap() as usize, LEN);
+ /// let mut buffer = aiocb.boxed_mut_slice().unwrap();
+ /// const EXPECT: &[u8] = b"cdef";
+ /// assert_eq!(buffer.borrow_mut(), EXPECT);
+ /// # }
+ /// ```
+ ///
+ /// [`from_boxed_slice`]: #method.from_boxed_slice
+ /// [`from_mut_slice`]: #method.from_mut_slice
+ pub fn from_boxed_mut_slice(fd: RawFd, offs: off_t,
+ mut buf: Box<BorrowMut<[u8]>>,
+ prio: libc::c_int, sigev_notify: SigevNotify,
+ opcode: LioOpcode) -> AioCb<'a> {
+ let mut a = AioCb::common_init(fd, prio, sigev_notify);
+ {
+ let borrowed : &mut BorrowMut<[u8]> = buf.borrow_mut();
+ let slice : &mut [u8] = borrowed.borrow_mut();
+ a.aio_nbytes = slice.len() as size_t;
+ a.aio_buf = slice.as_mut_ptr() as *mut c_void;
+ }
+ a.aio_offset = offs;
+ a.aio_lio_opcode = opcode as libc::c_int;
+
+ AioCb {
+ aiocb: a,
+ mutable: true,
+ in_progress: false,
+ buffer: Buffer::BoxedMutSlice(buf),
+ }
+ }
+
+ /// Constructs a new `AioCb` from a mutable raw pointer
+ ///
+ /// Unlike `from_mut_slice`, this method returns a structure suitable for
+ /// placement on the heap. It may be used for both reads and writes. Due
+ /// to its unsafety, this method is not recommended. It is most useful when
+ /// heap allocation is required but for some reason the data cannot be
+ /// wrapped in a `struct` that implements `BorrowMut<[u8]>`
+ ///
+ /// # Parameters
+ ///
+ /// * `fd`: File descriptor. Required for all aio functions.
+ /// * `offs`: File offset
+ /// * `buf`: Pointer to the memory buffer
+ /// * `len`: Length of the buffer pointed to by `buf`
+ /// * `prio`: If POSIX Prioritized IO is supported, then the
+ /// operation will be prioritized at the process's
+ /// priority level minus `prio`
+ /// * `sigev_notify`: Determines how you will be notified of event
+ /// completion.
+ /// * `opcode`: This field is only used for `lio_listio`. It
+ /// determines which operation to use for this individual
+ /// aiocb
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure that the storage pointed to by `buf` outlives the
+ /// `AioCb`. The lifetime checker can't help here.
+ pub unsafe fn from_mut_ptr(fd: RawFd, offs: off_t,
+ buf: *mut c_void, len: usize,
+ prio: libc::c_int, sigev_notify: SigevNotify,
+ opcode: LioOpcode) -> AioCb<'a> {
+ let mut a = AioCb::common_init(fd, prio, sigev_notify);
+ a.aio_offset = offs;
+ a.aio_nbytes = len;
+ a.aio_buf = buf;
+ a.aio_lio_opcode = opcode as libc::c_int;
+
+ AioCb {
+ aiocb: a,
+ mutable: true,
+ in_progress: false,
+ buffer: Buffer::None
+ }
+ }
+
+ /// Constructs a new `AioCb` from a raw pointer.
+ ///
+ /// Unlike `from_slice`, this method returns a structure suitable for
+ /// placement on the heap. Due to its unsafety, this method is not
+ /// recommended. It is most useful when heap allocation is required but for
+ /// some reason the data cannot be wrapped in a `struct` that implements
+ /// `Borrow<[u8]>`
+ ///
+ /// # Parameters
+ ///
+ /// * `fd`: File descriptor. Required for all aio functions.
+ /// * `offs`: File offset
+ /// * `buf`: Pointer to the memory buffer
+ /// * `len`: Length of the buffer pointed to by `buf`
+ /// * `prio`: If POSIX Prioritized IO is supported, then the
+ /// operation will be prioritized at the process's
+ /// priority level minus `prio`
+ /// * `sigev_notify`: Determines how you will be notified of event
+ /// completion.
+ /// * `opcode`: This field is only used for `lio_listio`. It
+ /// determines which operation to use for this individual
+ /// aiocb
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure that the storage pointed to by `buf` outlives the
+ /// `AioCb`. The lifetime checker can't help here.
+ pub unsafe fn from_ptr(fd: RawFd, offs: off_t,
+ buf: *const c_void, len: usize,
+ prio: libc::c_int, sigev_notify: SigevNotify,
+ opcode: LioOpcode) -> AioCb<'a> {
+ let mut a = AioCb::common_init(fd, prio, sigev_notify);
+ a.aio_offset = offs;
+ a.aio_nbytes = len;
+ // casting a const ptr to a mutable ptr here is ok, because we set the
+ // AioCb's mutable field to false
+ a.aio_buf = buf as *mut c_void;
+ a.aio_lio_opcode = opcode as libc::c_int;
+
+ AioCb {
+ aiocb: a,
+ mutable: false,
+ in_progress: false,
+ buffer: Buffer::None
+ }
+ }
+
+ /// Like `from_mut_slice`, but works on constant slices rather than
+ /// mutable slices.
+ ///
+ /// An `AioCb` created this way cannot be used with `read`, and its
+ /// `LioOpcode` cannot be set to `LIO_READ`. This method is useful when
+ /// writing a const buffer with `AioCb::write`, since `from_mut_slice` can't
+ /// work with const buffers.
+ ///
+ /// # Examples
+ ///
+ /// Construct an `AioCb` from a slice and use it for writing.
+ ///
+ /// ```
+ /// # extern crate tempfile;
+ /// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify;
+ /// # use std::{thread, time};
+ /// # use std::os::unix::io::AsRawFd;
+ /// # use tempfile::tempfile;
+ /// # fn main() {
+ /// const WBUF: &[u8] = b"abcdef123456";
+ /// let mut f = tempfile().unwrap();
+ /// let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
+ /// 2, //offset
+ /// WBUF,
+ /// 0, //priority
+ /// SigevNotify::SigevNone,
+ /// LioOpcode::LIO_NOP);
+ /// aiocb.write().unwrap();
+ /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
+ /// thread::sleep(time::Duration::from_millis(10));
+ /// }
+ /// assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len());
+ /// # }
+ /// ```
+ // Note: another solution to the problem of writing const buffers would be
+ // to genericize AioCb for both &mut [u8] and &[u8] buffers. AioCb::read
+ // could take the former and AioCb::write could take the latter. However,
+ // then lio_listio wouldn't work, because that function needs a slice of
+ // AioCb, and they must all be of the same type.
+ pub fn from_slice(fd: RawFd, offs: off_t, buf: &'a [u8],
+ prio: libc::c_int, sigev_notify: SigevNotify,
+ opcode: LioOpcode) -> AioCb {
+ let mut a = AioCb::common_init(fd, prio, sigev_notify);
+ a.aio_offset = offs;
+ a.aio_nbytes = buf.len() as size_t;
+ // casting an immutable buffer to a mutable pointer looks unsafe,
+ // but technically its only unsafe to dereference it, not to create
+ // it.
+ a.aio_buf = buf.as_ptr() as *mut c_void;
+ assert!(opcode != LioOpcode::LIO_READ, "Can't read into an immutable buffer");
+ a.aio_lio_opcode = opcode as libc::c_int;
+
+ AioCb {
+ aiocb: a,
+ mutable: false,
+ in_progress: false,
+ buffer: Buffer::None,
+ }
+ }
+
+ fn common_init(fd: RawFd, prio: libc::c_int,
+ sigev_notify: SigevNotify) -> libc::aiocb {
+ // Use mem::zeroed instead of explicitly zeroing each field, because the
+ // number and name of reserved fields is OS-dependent. On some OSes,
+ // some reserved fields are used the kernel for state, and must be
+ // explicitly zeroed when allocated.
+ let mut a = unsafe { mem::zeroed::<libc::aiocb>()};
+ a.aio_fildes = fd;
+ a.aio_reqprio = prio;
+ a.aio_sigevent = SigEvent::new(sigev_notify).sigevent();
+ a
+ }
+
+ /// Update the notification settings for an existing `aiocb`
+ pub fn set_sigev_notify(&mut self, sigev_notify: SigevNotify) {
+ self.aiocb.aio_sigevent = SigEvent::new(sigev_notify).sigevent();
+ }
+
+ /// Cancels an outstanding AIO request.
+ ///
+ /// The operating system is not required to implement cancellation for all
+ /// file and device types. Even if it does, there is no guarantee that the
+ /// operation has not already completed. So the caller must check the
+ /// result and handle operations that were not canceled or that have already
+ /// completed.
+ ///
+ /// # Examples
+ ///
+ /// Cancel an outstanding aio operation. Note that we must still call
+ /// `aio_return` to free resources, even though we don't care about the
+ /// result.
+ ///
+ /// ```
+ /// # extern crate tempfile;
+ /// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify;
+ /// # use std::{thread, time};
+ /// # use std::io::Write;
+ /// # use std::os::unix::io::AsRawFd;
+ /// # use tempfile::tempfile;
+ /// # fn main() {
+ /// let wbuf = b"CDEF";
+ /// let mut f = tempfile().unwrap();
+ /// let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
+ /// 2, //offset
+ /// &wbuf[..],
+ /// 0, //priority
+ /// SigevNotify::SigevNone,
+ /// LioOpcode::LIO_NOP);
+ /// aiocb.write().unwrap();
+ /// let cs = aiocb.cancel().unwrap();
+ /// if cs == AioCancelStat::AioNotCanceled {
+ /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
+ /// thread::sleep(time::Duration::from_millis(10));
+ /// }
+ /// }
+ /// // Must call `aio_return`, but ignore the result
+ /// let _ = aiocb.aio_return();
+ /// # }
+ /// ```
+ ///
+ /// # References
+ ///
+ /// [aio_cancel](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html)
+ pub fn cancel(&mut self) -> Result<AioCancelStat> {
+ match unsafe { libc::aio_cancel(self.aiocb.aio_fildes, &mut self.aiocb) } {
+ libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled),
+ libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled),
+ libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone),
+ -1 => Err(Error::last()),
+ _ => panic!("unknown aio_cancel return value")
+ }
+ }
+
+ /// Retrieve error status of an asynchronous operation.
+ ///
+ /// If the request has not yet completed, returns `EINPROGRESS`. Otherwise,
+ /// returns `Ok` or any other error.
+ ///
+ /// # Examples
+ ///
+ /// Issue an aio operation and use `error` to poll for completion. Polling
+ /// is an alternative to `aio_suspend`, used by most of the other examples.
+ ///
+ /// ```
+ /// # extern crate tempfile;
+ /// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify;
+ /// # use std::{thread, time};
+ /// # use std::os::unix::io::AsRawFd;
+ /// # use tempfile::tempfile;
+ /// # fn main() {
+ /// const WBUF: &[u8] = b"abcdef123456";
+ /// let mut f = tempfile().unwrap();
+ /// let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
+ /// 2, //offset
+ /// WBUF,
+ /// 0, //priority
+ /// SigevNotify::SigevNone,
+ /// LioOpcode::LIO_NOP);
+ /// aiocb.write().unwrap();
+ /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
+ /// thread::sleep(time::Duration::from_millis(10));
+ /// }
+ /// assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len());
+ /// # }
+ /// ```
+ ///
+ /// # References
+ ///
+ /// [aio_error](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_error.html)
+ pub fn error(&mut self) -> Result<()> {
+ match unsafe { libc::aio_error(&mut self.aiocb as *mut libc::aiocb) } {
+ 0 => Ok(()),
+ num if num > 0 => Err(Error::from_errno(Errno::from_i32(num))),
+ -1 => Err(Error::last()),
+ num => panic!("unknown aio_error return value {:?}", num)
+ }
+ }
+
+ /// An asynchronous version of `fsync(2)`.
+ ///
+ /// # References
+ ///
+ /// [aio_fsync](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_fsync.html)
+ pub fn fsync(&mut self, mode: AioFsyncMode) -> Result<()> {
+ let p: *mut libc::aiocb = &mut self.aiocb;
+ Errno::result(unsafe {
+ libc::aio_fsync(mode as libc::c_int, p)
+ }).map(|_| {
+ self.in_progress = true;
+ })
+ }
+
+ /// Returns the `aiocb`'s `LioOpcode` field
+ ///
+ /// If the value cannot be represented as an `LioOpcode`, returns `None`
+ /// instead.
+ pub fn lio_opcode(&self) -> Option<LioOpcode> {
+ match self.aiocb.aio_lio_opcode {
+ libc::LIO_READ => Some(LioOpcode::LIO_READ),
+ libc::LIO_WRITE => Some(LioOpcode::LIO_WRITE),
+ libc::LIO_NOP => Some(LioOpcode::LIO_NOP),
+ _ => None
+ }
+ }
+
+ /// Returns the requested length of the aio operation in bytes
+ ///
+ /// This method returns the *requested* length of the operation. To get the
+ /// number of bytes actually read or written by a completed operation, use
+ /// `aio_return` instead.
+ pub fn nbytes(&self) -> usize {
+ self.aiocb.aio_nbytes
+ }
+
+ /// Returns the file offset stored in the `AioCb`
+ pub fn offset(&self) -> off_t {
+ self.aiocb.aio_offset
+ }
+
+ /// Returns the priority of the `AioCb`
+ pub fn priority(&self) -> libc::c_int {
+ self.aiocb.aio_reqprio
+ }
+
+ /// Asynchronously reads from a file descriptor into a buffer
+ ///
+ /// # References
+ ///
+ /// [aio_read](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_read.html)
+ pub fn read(&mut self) -> Result<()> {
+ assert!(self.mutable, "Can't read into an immutable buffer");
+ let p: *mut libc::aiocb = &mut self.aiocb;
+ Errno::result(unsafe {
+ libc::aio_read(p)
+ }).map(|_| {
+ self.in_progress = true;
+ })
+ }
+
+ /// Returns the `SigEvent` stored in the `AioCb`
+ pub fn sigevent(&self) -> SigEvent {
+ SigEvent::from(&self.aiocb.aio_sigevent)
+ }
+
+ /// Retrieve return status of an asynchronous operation.
+ ///
+ /// Should only be called once for each `AioCb`, after `AioCb::error`
+ /// indicates that it has completed. The result is the same as for the
+ /// synchronous `read(2)`, `write(2)`, of `fsync(2)` functions.
+ ///
+ /// # References
+ ///
+ /// [aio_return](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_return.html)
+ // Note: this should be just `return`, but that's a reserved word
+ pub fn aio_return(&mut self) -> Result<isize> {
+ let p: *mut libc::aiocb = &mut self.aiocb;
+ self.in_progress = false;
+ Errno::result(unsafe { libc::aio_return(p) })
+ }
+
+ /// Asynchronously writes from a buffer to a file descriptor
+ ///
+ /// # References
+ ///
+ /// [aio_write](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_write.html)
+ pub fn write(&mut self) -> Result<()> {
+ let p: *mut libc::aiocb = &mut self.aiocb;
+ Errno::result(unsafe {
+ libc::aio_write(p)
+ }).map(|_| {
+ self.in_progress = true;
+ })
+ }
+
+}
+
+/// Cancels outstanding AIO requests for a given file descriptor.
+///
+/// # Examples
+///
+/// Issue an aio operation, then cancel all outstanding operations on that file
+/// descriptor.
+///
+/// ```
+/// # extern crate tempfile;
+/// # extern crate nix;
+/// # use nix::errno::Errno;
+/// # use nix::Error;
+/// # use nix::sys::aio::*;
+/// # use nix::sys::signal::SigevNotify;
+/// # use std::{thread, time};
+/// # use std::io::Write;
+/// # use std::os::unix::io::AsRawFd;
+/// # use tempfile::tempfile;
+/// # fn main() {
+/// let wbuf = b"CDEF";
+/// let mut f = tempfile().unwrap();
+/// let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
+/// 2, //offset
+/// &wbuf[..],
+/// 0, //priority
+/// SigevNotify::SigevNone,
+/// LioOpcode::LIO_NOP);
+/// aiocb.write().unwrap();
+/// let cs = aio_cancel_all(f.as_raw_fd()).unwrap();
+/// if cs == AioCancelStat::AioNotCanceled {
+/// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
+/// thread::sleep(time::Duration::from_millis(10));
+/// }
+/// }
+/// // Must call `aio_return`, but ignore the result
+/// let _ = aiocb.aio_return();
+/// # }
+/// ```
+///
+/// # References
+///
+/// [`aio_cancel`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html)
+pub fn aio_cancel_all(fd: RawFd) -> Result<AioCancelStat> {
+ match unsafe { libc::aio_cancel(fd, null_mut()) } {
+ libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled),
+ libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled),
+ libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone),
+ -1 => Err(Error::last()),
+ _ => panic!("unknown aio_cancel return value")
+ }
+}
+
+/// Suspends the calling process until at least one of the specified `AioCb`s
+/// has completed, a signal is delivered, or the timeout has passed.
+///
+/// If `timeout` is `None`, `aio_suspend` will block indefinitely.
+///
+/// # Examples
+///
+/// Use `aio_suspend` to block until an aio operation completes.
+///
+// Disable doctest due to a known bug in FreeBSD's 32-bit emulation. The fix
+// will be included in release 11.2.
+// FIXME reenable the doc test when the CI machine gets upgraded to that release.
+// https://svnweb.freebsd.org/base?view=revision&revision=325018
+/// ```no_run
+/// # extern crate tempfile;
+/// # extern crate nix;
+/// # use nix::sys::aio::*;
+/// # use nix::sys::signal::SigevNotify;
+/// # use std::os::unix::io::AsRawFd;
+/// # use tempfile::tempfile;
+/// # fn main() {
+/// const WBUF: &[u8] = b"abcdef123456";
+/// let mut f = tempfile().unwrap();
+/// let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
+/// 2, //offset
+/// WBUF,
+/// 0, //priority
+/// SigevNotify::SigevNone,
+/// LioOpcode::LIO_NOP);
+/// aiocb.write().unwrap();
+/// aio_suspend(&[&aiocb], None).expect("aio_suspend failed");
+/// assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len());
+/// # }
+/// ```
+/// # References
+///
+/// [`aio_suspend`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_suspend.html)
+pub fn aio_suspend(list: &[&AioCb], timeout: Option<TimeSpec>) -> Result<()> {
+ let plist = list as *const [&AioCb] as *const [*const libc::aiocb];
+ let p = plist as *const *const libc::aiocb;
+ let timep = match timeout {
+ None => null::<libc::timespec>(),
+ Some(x) => x.as_ref() as *const libc::timespec
+ };
+ Errno::result(unsafe {
+ libc::aio_suspend(p, list.len() as i32, timep)
+ }).map(drop)
+}
+
+impl<'a> Debug for AioCb<'a> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_struct("AioCb")
+ .field("aio_fildes", &self.aiocb.aio_fildes)
+ .field("aio_offset", &self.aiocb.aio_offset)
+ .field("aio_buf", &self.aiocb.aio_buf)
+ .field("aio_nbytes", &self.aiocb.aio_nbytes)
+ .field("aio_lio_opcode", &self.aiocb.aio_lio_opcode)
+ .field("aio_reqprio", &self.aiocb.aio_reqprio)
+ .field("aio_sigevent", &SigEvent::from(&self.aiocb.aio_sigevent))
+ .field("mutable", &self.mutable)
+ .field("in_progress", &self.in_progress)
+ .finish()
+ }
+}
+
+impl<'a> Drop for AioCb<'a> {
+ /// If the `AioCb` has no remaining state in the kernel, just drop it.
+ /// Otherwise, dropping constitutes a resource leak, which is an error
+ fn drop(&mut self) {
+ assert!(thread::panicking() || !self.in_progress,
+ "Dropped an in-progress AioCb");
+ }
+}
+
+/// LIO Control Block.
+///
+/// The basic structure used to issue multiple AIO operations simultaneously.
+#[cfg(not(any(target_os = "ios", target_os = "macos")))]
+pub struct LioCb<'a> {
+ /// A collection of [`AioCb`]s. All of these will be issued simultaneously
+ /// by the [`listio`] method.
+ ///
+ /// [`AioCb`]: struct.AioCb.html
+ /// [`listio`]: #method.listio
+ pub aiocbs: Vec<AioCb<'a>>,
+
+ /// The actual list passed to `libc::lio_listio`.
+ ///
+ /// It must live for as long as any of the operations are still being
+ /// processesed, because the aio subsystem uses its address as a unique
+ /// identifier.
+ list: Vec<*mut libc::aiocb>,
+
+ /// A partial set of results. This field will get populated by
+ /// `listio_resubmit` when an `LioCb` is resubmitted after an error
+ results: Vec<Option<Result<isize>>>
+}
+
+#[cfg(not(any(target_os = "ios", target_os = "macos")))]
+impl<'a> LioCb<'a> {
+ /// Initialize an empty `LioCb`
+ pub fn with_capacity(capacity: usize) -> LioCb<'a> {
+ LioCb {
+ aiocbs: Vec::with_capacity(capacity),
+ list: Vec::with_capacity(capacity),
+ results: Vec::with_capacity(capacity)
+ }
+ }
+
+ /// Submits multiple asynchronous I/O requests with a single system call.
+ ///
+ /// They are not guaranteed to complete atomically, and the order in which
+ /// the requests are carried out is not specified. Reads, writes, and
+ /// fsyncs may be freely mixed.
+ ///
+ /// This function is useful for reducing the context-switch overhead of
+ /// submitting many AIO operations. It can also be used with
+ /// `LioMode::LIO_WAIT` to block on the result of several independent
+ /// operations. Used that way, it is often useful in programs that
+ /// otherwise make little use of AIO.
+ ///
+ /// # Examples
+ ///
+ /// Use `listio` to submit an aio operation and wait for its completion. In
+ /// this case, there is no need to use [`aio_suspend`] to wait or
+ /// [`AioCb::error`] to poll.
+ ///
+ /// ```
+ /// # extern crate tempfile;
+ /// # extern crate nix;
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify;
+ /// # use std::os::unix::io::AsRawFd;
+ /// # use tempfile::tempfile;
+ /// # fn main() {
+ /// const WBUF: &[u8] = b"abcdef123456";
+ /// let mut f = tempfile().unwrap();
+ /// let mut liocb = LioCb::with_capacity(1);
+ /// liocb.aiocbs.push(AioCb::from_slice( f.as_raw_fd(),
+ /// 2, //offset
+ /// WBUF,
+ /// 0, //priority
+ /// SigevNotify::SigevNone,
+ /// LioOpcode::LIO_WRITE));
+ /// liocb.listio(LioMode::LIO_WAIT,
+ /// SigevNotify::SigevNone).unwrap();
+ /// assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len());
+ /// # }
+ /// ```
+ ///
+ /// # References
+ ///
+ /// [`lio_listio`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lio_listio.html)
+ ///
+ /// [`aio_suspend`]: fn.aio_suspend.html
+ /// [`AioCb::error`]: struct.AioCb.html#method.error
+ pub fn listio(&mut self, mode: LioMode,
+ sigev_notify: SigevNotify) -> Result<()> {
+ let sigev = SigEvent::new(sigev_notify);
+ let sigevp = &mut sigev.sigevent() as *mut libc::sigevent;
+ self.list.clear();
+ for a in &mut self.aiocbs {
+ a.in_progress = true;
+ self.list.push(a as *mut AioCb<'a>
+ as *mut libc::aiocb);
+ }
+ let p = self.list.as_ptr();
+ Errno::result(unsafe {
+ libc::lio_listio(mode as i32, p, self.list.len() as i32, sigevp)
+ }).map(drop)
+ }
+
+ /// Resubmits any incomplete operations with [`lio_listio`].
+ ///
+ /// Sometimes, due to system resource limitations, an `lio_listio` call will
+ /// return `EIO`, or `EAGAIN`. Or, if a signal is received, it may return
+ /// `EINTR`. In any of these cases, only a subset of its constituent
+ /// operations will actually have been initiated. `listio_resubmit` will
+ /// resubmit any operations that are still uninitiated.
+ ///
+ /// After calling `listio_resubmit`, results should be collected by
+ /// [`LioCb::aio_return`].
+ ///
+ /// # Examples
+ /// ```no_run
+ /// # extern crate tempfile;
+ /// # extern crate nix;
+ /// # use nix::Error;
+ /// # use nix::errno::Errno;
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify;
+ /// # use std::os::unix::io::AsRawFd;
+ /// # use std::{thread, time};
+ /// # use tempfile::tempfile;
+ /// # fn main() {
+ /// const WBUF: &[u8] = b"abcdef123456";
+ /// let mut f = tempfile().unwrap();
+ /// let mut liocb = LioCb::with_capacity(1);
+ /// liocb.aiocbs.push(AioCb::from_slice( f.as_raw_fd(),
+ /// 2, //offset
+ /// WBUF,
+ /// 0, //priority
+ /// SigevNotify::SigevNone,
+ /// LioOpcode::LIO_WRITE));
+ /// let mut err = liocb.listio(LioMode::LIO_WAIT, SigevNotify::SigevNone);
+ /// while err == Err(Error::Sys(Errno::EIO)) ||
+ /// err == Err(Error::Sys(Errno::EAGAIN)) {
+ /// thread::sleep(time::Duration::from_millis(10));
+ /// err = liocb.listio_resubmit(LioMode::LIO_WAIT, SigevNotify::SigevNone);
+ /// }
+ /// assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len());
+ /// # }
+ /// ```
+ ///
+ /// # References
+ ///
+ /// [`lio_listio`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lio_listio.html)
+ ///
+ /// [`lio_listio`]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/lio_listio.html
+ /// [`LioCb::aio_return`]: struct.LioCb.html#method.aio_return
+ // Note: the addresses of any EINPROGRESS or EOK aiocbs _must_ not be
+ // changed by this method, because the kernel relies on their addresses
+ // being stable.
+ // Note: aiocbs that are Ok(()) must be finalized by aio_return, or else the
+ // sigev_notify will immediately refire.
+ pub fn listio_resubmit(&mut self, mode:LioMode,
+ sigev_notify: SigevNotify) -> Result<()> {
+ let sigev = SigEvent::new(sigev_notify);
+ let sigevp = &mut sigev.sigevent() as *mut libc::sigevent;
+ self.list.clear();
+
+ while self.results.len() < self.aiocbs.len() {
+ self.results.push(None);
+ }
+
+ for (i, a) in self.aiocbs.iter_mut().enumerate() {
+ if self.results[i].is_some() {
+ // Already collected final status for this operation
+ continue;
+ }
+ match a.error() {
+ Ok(()) => {
+ // aiocb is complete; collect its status and don't resubmit
+ self.results[i] = Some(a.aio_return());
+ },
+ Err(Error::Sys(Errno::EAGAIN)) => {
+ self.list.push(a as *mut AioCb<'a> as *mut libc::aiocb);
+ },
+ Err(Error::Sys(Errno::EINPROGRESS)) => {
+ // aiocb is was successfully queued; no need to do anything
+ ()
+ },
+ Err(Error::Sys(Errno::EINVAL)) => panic!(
+ "AioCb was never submitted, or already finalized"),
+ _ => unreachable!()
+ }
+ }
+ let p = self.list.as_ptr();
+ Errno::result(unsafe {
+ libc::lio_listio(mode as i32, p, self.list.len() as i32, sigevp)
+ }).map(drop)
+ }
+
+ /// Collect final status for an individual `AioCb` submitted as part of an
+ /// `LioCb`.
+ ///
+ /// This is just like [`AioCb::aio_return`], except it takes into account
+ /// operations that were restarted by [`LioCb::listio_resubmit`]
+ ///
+ /// [`AioCb::aio_return`]: struct.AioCb.html#method.aio_return
+ /// [`LioCb::listio_resubmit`]: #method.listio_resubmit
+ pub fn aio_return(&mut self, i: usize) -> Result<isize> {
+ if i >= self.results.len() || self.results[i].is_none() {
+ self.aiocbs[i].aio_return()
+ } else {
+ self.results[i].unwrap()
+ }
+ }
+
+ /// Retrieve error status of an individual `AioCb` submitted as part of an
+ /// `LioCb`.
+ ///
+ /// This is just like [`AioCb::error`], except it takes into account
+ /// operations that were restarted by [`LioCb::listio_resubmit`]
+ ///
+ /// [`AioCb::error`]: struct.AioCb.html#method.error
+ /// [`LioCb::listio_resubmit`]: #method.listio_resubmit
+ pub fn error(&mut self, i: usize) -> Result<()> {
+ if i >= self.results.len() || self.results[i].is_none() {
+ self.aiocbs[i].error()
+ } else {
+ Ok(())
+ }
+ }
+}
+
+#[cfg(not(any(target_os = "ios", target_os = "macos")))]
+impl<'a> Debug for LioCb<'a> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_struct("LioCb")
+ .field("aiocbs", &self.aiocbs)
+ .finish()
+ }
+}
+
+#[cfg(not(any(target_os = "ios", target_os = "macos")))]
+impl<'a> From<Vec<AioCb<'a>>> for LioCb<'a> {
+ fn from(src: Vec<AioCb<'a>>) -> LioCb<'a> {
+ LioCb {
+ list: Vec::with_capacity(src.capacity()),
+ results: Vec::with_capacity(src.capacity()),
+ aiocbs: src,
+ }
+ }
+}
diff --git a/third_party/rust/nix/src/sys/epoll.rs b/third_party/rust/nix/src/sys/epoll.rs
new file mode 100644
index 0000000000..3ed1dd7240
--- /dev/null
+++ b/third_party/rust/nix/src/sys/epoll.rs
@@ -0,0 +1,110 @@
+use Result;
+use errno::Errno;
+use libc::{self, c_int};
+use std::os::unix::io::RawFd;
+use std::ptr;
+use std::mem;
+use ::Error;
+
+libc_bitflags!(
+ pub struct EpollFlags: c_int {
+ EPOLLIN;
+ EPOLLPRI;
+ EPOLLOUT;
+ EPOLLRDNORM;
+ EPOLLRDBAND;
+ EPOLLWRNORM;
+ EPOLLWRBAND;
+ EPOLLMSG;
+ EPOLLERR;
+ EPOLLHUP;
+ EPOLLRDHUP;
+ #[cfg(target_os = "linux")] // Added in 4.5; not in Android.
+ EPOLLEXCLUSIVE;
+ #[cfg(not(target_arch = "mips"))]
+ EPOLLWAKEUP;
+ EPOLLONESHOT;
+ EPOLLET;
+ }
+);
+
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+#[repr(i32)]
+pub enum EpollOp {
+ EpollCtlAdd = libc::EPOLL_CTL_ADD,
+ EpollCtlDel = libc::EPOLL_CTL_DEL,
+ EpollCtlMod = libc::EPOLL_CTL_MOD,
+}
+
+libc_bitflags!{
+ pub struct EpollCreateFlags: c_int {
+ EPOLL_CLOEXEC;
+ }
+}
+
+#[allow(missing_debug_implementations)]
+#[derive(Clone, Copy)]
+#[repr(C)]
+pub struct EpollEvent {
+ event: libc::epoll_event,
+}
+
+impl EpollEvent {
+ pub fn new(events: EpollFlags, data: u64) -> Self {
+ EpollEvent { event: libc::epoll_event { events: events.bits() as u32, u64: data } }
+ }
+
+ pub fn empty() -> Self {
+ unsafe { mem::zeroed::<EpollEvent>() }
+ }
+
+ pub fn events(&self) -> EpollFlags {
+ EpollFlags::from_bits(self.event.events as c_int).unwrap()
+ }
+
+ pub fn data(&self) -> u64 {
+ self.event.u64
+ }
+}
+
+#[inline]
+pub fn epoll_create() -> Result<RawFd> {
+ let res = unsafe { libc::epoll_create(1024) };
+
+ Errno::result(res)
+}
+
+#[inline]
+pub fn epoll_create1(flags: EpollCreateFlags) -> Result<RawFd> {
+ let res = unsafe { libc::epoll_create1(flags.bits()) };
+
+ Errno::result(res)
+}
+
+#[inline]
+pub fn epoll_ctl<'a, T>(epfd: RawFd, op: EpollOp, fd: RawFd, event: T) -> Result<()>
+ where T: Into<Option<&'a mut EpollEvent>>
+{
+ let mut event: Option<&mut EpollEvent> = event.into();
+ if event.is_none() && op != EpollOp::EpollCtlDel {
+ Err(Error::Sys(Errno::EINVAL))
+ } else {
+ let res = unsafe {
+ if let Some(ref mut event) = event {
+ libc::epoll_ctl(epfd, op as c_int, fd, &mut event.event)
+ } else {
+ libc::epoll_ctl(epfd, op as c_int, fd, ptr::null_mut())
+ }
+ };
+ Errno::result(res).map(drop)
+ }
+}
+
+#[inline]
+pub fn epoll_wait(epfd: RawFd, events: &mut [EpollEvent], timeout_ms: isize) -> Result<usize> {
+ let res = unsafe {
+ libc::epoll_wait(epfd, events.as_mut_ptr() as *mut libc::epoll_event, events.len() as c_int, timeout_ms as c_int)
+ };
+
+ Errno::result(res).map(|r| r as usize)
+}
diff --git a/third_party/rust/nix/src/sys/event.rs b/third_party/rust/nix/src/sys/event.rs
new file mode 100644
index 0000000000..f1eaa0d155
--- /dev/null
+++ b/third_party/rust/nix/src/sys/event.rs
@@ -0,0 +1,352 @@
+/* TOOD: Implement for other kqueue based systems
+ */
+
+use {Errno, Result};
+#[cfg(not(target_os = "netbsd"))]
+use libc::{timespec, time_t, c_int, c_long, intptr_t, uintptr_t};
+#[cfg(target_os = "netbsd")]
+use libc::{timespec, time_t, c_long, intptr_t, uintptr_t, size_t};
+use libc;
+use std::os::unix::io::RawFd;
+use std::ptr;
+use std::mem;
+
+// Redefine kevent in terms of programmer-friendly enums and bitfields.
+#[derive(Clone, Copy)]
+#[repr(C)]
+#[allow(missing_debug_implementations)]
+pub struct KEvent {
+ kevent: libc::kevent,
+}
+
+#[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 = "dragonfly", target_os = "freebsd",
+ target_os = "ios", target_os = "macos"))]
+type type_of_data = intptr_t;
+#[cfg(any(target_os = "netbsd"))]
+type type_of_udata = intptr_t;
+#[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
+type type_of_data = libc::int64_t;
+
+#[cfg(target_os = "netbsd")]
+type type_of_event_filter = u32;
+#[cfg(not(target_os = "netbsd"))]
+type type_of_event_filter = i16;
+libc_enum! {
+ #[cfg_attr(target_os = "netbsd", repr(u32))]
+ #[cfg_attr(not(target_os = "netbsd"), repr(i16))]
+ pub enum EventFilter {
+ EVFILT_AIO,
+ /// Returns whenever there is no remaining data in the write buffer
+ #[cfg(target_os = "freebsd")]
+ EVFILT_EMPTY,
+ #[cfg(target_os = "dragonfly")]
+ EVFILT_EXCEPT,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos"))]
+ EVFILT_FS,
+ #[cfg(target_os = "freebsd")]
+ EVFILT_LIO,
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ EVFILT_MACHPORT,
+ EVFILT_PROC,
+ /// Returns events associated with the process referenced by a given
+ /// process descriptor, created by `pdfork()`. The events to monitor are:
+ ///
+ /// - NOTE_EXIT: the process has exited. The exit status will be stored in data.
+ #[cfg(target_os = "freebsd")]
+ EVFILT_PROCDESC,
+ EVFILT_READ,
+ /// Returns whenever an asynchronous `sendfile()` call completes.
+ #[cfg(target_os = "freebsd")]
+ EVFILT_SENDFILE,
+ EVFILT_SIGNAL,
+ EVFILT_TIMER,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos"))]
+ EVFILT_USER,
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ EVFILT_VM,
+ EVFILT_VNODE,
+ EVFILT_WRITE,
+ }
+}
+
+#[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"))]
+pub type type_of_event_flag = u32;
+libc_bitflags!{
+ pub struct 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;
+ EV_ENABLE;
+ EV_EOF;
+ EV_ERROR;
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ EV_FLAG0;
+ EV_FLAG1;
+ #[cfg(target_os = "dragonfly")]
+ EV_NODATA;
+ EV_ONESHOT;
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ EV_OOBAND;
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ EV_POLL;
+ #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
+ target_os = "ios", target_os = "macos",
+ target_os = "netbsd"))]
+ EV_RECEIPT;
+ EV_SYSFLAGS;
+ }
+}
+
+libc_bitflags!(
+ pub struct FilterFlag: u32 {
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ NOTE_ABSOLUTE;
+ NOTE_ATTRIB;
+ NOTE_CHILD;
+ NOTE_DELETE;
+ #[cfg(target_os = "openbsd")]
+ NOTE_EOF;
+ NOTE_EXEC;
+ NOTE_EXIT;
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ #[deprecated( since="0.14.0", note="Deprecated since OSX 10.9")]
+ #[allow(deprecated)]
+ NOTE_EXIT_REPARENTED;
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ NOTE_EXITSTATUS;
+ NOTE_EXTEND;
+ #[cfg(any(target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "dragonfly"))]
+ NOTE_FFAND;
+ #[cfg(any(target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "dragonfly"))]
+ NOTE_FFCOPY;
+ #[cfg(any(target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "dragonfly"))]
+ NOTE_FFCTRLMASK;
+ #[cfg(any(target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "dragonfly"))]
+ NOTE_FFLAGSMASK;
+ #[cfg(any(target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "dragonfly"))]
+ NOTE_FFNOP;
+ #[cfg(any(target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "dragonfly"))]
+ NOTE_FFOR;
+ NOTE_FORK;
+ NOTE_LINK;
+ NOTE_LOWAT;
+ #[cfg(target_os = "freebsd")]
+ NOTE_MSECONDS;
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ NOTE_NONE;
+ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
+ NOTE_NSECONDS;
+ #[cfg(target_os = "dragonfly")]
+ NOTE_OOB;
+ NOTE_PCTRLMASK;
+ NOTE_PDATAMASK;
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ #[deprecated( since="0.14.0", note="Deprecated since OSX 10.9")]
+ #[allow(deprecated)]
+ NOTE_REAP;
+ NOTE_RENAME;
+ NOTE_REVOKE;
+ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
+ NOTE_SECONDS;
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ NOTE_SIGNAL;
+ NOTE_TRACK;
+ NOTE_TRACKERR;
+ #[cfg(any(target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "dragonfly"))]
+ NOTE_TRIGGER;
+ #[cfg(target_os = "openbsd")]
+ NOTE_TRUNCATE;
+ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
+ NOTE_USECONDS;
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ NOTE_VM_ERROR;
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ NOTE_VM_PRESSURE;
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ NOTE_VM_PRESSURE_SUDDEN_TERMINATE;
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ NOTE_VM_PRESSURE_TERMINATE;
+ NOTE_WRITE;
+ }
+);
+
+pub fn kqueue() -> Result<RawFd> {
+ let res = unsafe { libc::kqueue() };
+
+ Errno::result(res)
+}
+
+
+// KEvent can't derive Send because on some operating systems, udata is defined
+// as a void*. However, KEvent's public API always treats udata as an intptr_t,
+// which is safe to Send.
+unsafe impl Send for KEvent {
+}
+
+impl KEvent {
+ pub fn new(ident: uintptr_t, filter: EventFilter, flags: EventFlag,
+ fflags:FilterFlag, data: intptr_t, udata: intptr_t) -> KEvent {
+ KEvent { kevent: libc::kevent {
+ ident: ident,
+ filter: filter as type_of_event_filter,
+ flags: flags.bits(),
+ fflags: fflags.bits(),
+ data: data as type_of_data,
+ udata: udata as type_of_udata
+ } }
+ }
+
+ pub fn ident(&self) -> uintptr_t {
+ self.kevent.ident
+ }
+
+ pub fn filter(&self) -> EventFilter {
+ unsafe { mem::transmute(self.kevent.filter as type_of_event_filter) }
+ }
+
+ pub fn flags(&self) -> EventFlag {
+ EventFlag::from_bits(self.kevent.flags).unwrap()
+ }
+
+ pub fn fflags(&self) -> FilterFlag {
+ FilterFlag::from_bits(self.kevent.fflags).unwrap()
+ }
+
+ pub fn data(&self) -> intptr_t {
+ self.kevent.data as intptr_t
+ }
+
+ pub fn udata(&self) -> intptr_t {
+ self.kevent.udata as intptr_t
+ }
+}
+
+pub fn kevent(kq: RawFd,
+ changelist: &[KEvent],
+ eventlist: &mut [KEvent],
+ timeout_ms: usize) -> Result<usize> {
+
+ // Convert ms to timespec
+ let timeout = timespec {
+ tv_sec: (timeout_ms / 1000) as time_t,
+ tv_nsec: ((timeout_ms % 1000) * 1_000_000) as c_long
+ };
+
+ kevent_ts(kq, changelist, eventlist, Some(timeout))
+}
+
+#[cfg(any(target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "dragonfly",
+ target_os = "openbsd"))]
+type type_of_nchanges = c_int;
+#[cfg(target_os = "netbsd")]
+type type_of_nchanges = size_t;
+
+pub fn kevent_ts(kq: RawFd,
+ changelist: &[KEvent],
+ eventlist: &mut [KEvent],
+ timeout_opt: Option<timespec>) -> Result<usize> {
+
+ let res = unsafe {
+ libc::kevent(
+ kq,
+ changelist.as_ptr() as *const libc::kevent,
+ changelist.len() as type_of_nchanges,
+ eventlist.as_mut_ptr() as *mut libc::kevent,
+ eventlist.len() as type_of_nchanges,
+ if let Some(ref timeout) = timeout_opt {timeout as *const timespec} else {ptr::null()})
+ };
+
+ Errno::result(res).map(|r| r as usize)
+}
+
+#[inline]
+pub fn ev_set(ev: &mut KEvent,
+ ident: usize,
+ filter: EventFilter,
+ flags: EventFlag,
+ fflags: FilterFlag,
+ udata: intptr_t) {
+
+ ev.kevent.ident = ident as uintptr_t;
+ ev.kevent.filter = filter as type_of_event_filter;
+ ev.kevent.flags = flags.bits();
+ ev.kevent.fflags = fflags.bits();
+ ev.kevent.data = 0;
+ ev.kevent.udata = udata as type_of_udata;
+}
+
+#[test]
+fn test_struct_kevent() {
+ let udata : intptr_t = 12345;
+
+ let expected = libc::kevent{ident: 0xdead_beef,
+ filter: libc::EVFILT_READ,
+ 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(0xdead_beef,
+ EventFilter::EVFILT_READ,
+ EventFlag::EV_ONESHOT | EventFlag::EV_ADD,
+ FilterFlag::NOTE_CHILD | FilterFlag::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() as type_of_data);
+ assert!(expected.udata == actual.udata() as type_of_udata);
+ assert!(mem::size_of::<libc::kevent>() == mem::size_of::<KEvent>());
+}
diff --git a/third_party/rust/nix/src/sys/eventfd.rs b/third_party/rust/nix/src/sys/eventfd.rs
new file mode 100644
index 0000000000..c5a54e46a1
--- /dev/null
+++ b/third_party/rust/nix/src/sys/eventfd.rs
@@ -0,0 +1,18 @@
+use libc;
+use std::os::unix::io::RawFd;
+use Result;
+use errno::Errno;
+
+libc_bitflags! {
+ pub struct EfdFlags: libc::c_int {
+ EFD_CLOEXEC; // Since Linux 2.6.27
+ EFD_NONBLOCK; // Since Linux 2.6.27
+ EFD_SEMAPHORE; // Since Linux 2.6.30
+ }
+}
+
+pub fn eventfd(initval: libc::c_uint, flags: EfdFlags) -> Result<RawFd> {
+ let res = unsafe { libc::eventfd(initval, flags.bits()) };
+
+ Errno::result(res).map(|r| r as RawFd)
+}
diff --git a/third_party/rust/nix/src/sys/ioctl/bsd.rs b/third_party/rust/nix/src/sys/ioctl/bsd.rs
new file mode 100644
index 0000000000..4c39fa6a05
--- /dev/null
+++ b/third_party/rust/nix/src/sys/ioctl/bsd.rs
@@ -0,0 +1,102 @@
+/// The datatype used for the ioctl number
+#[doc(hidden)]
+pub type ioctl_num_type = ::libc::c_ulong;
+/// The datatype used for the 3rd argument
+#[doc(hidden)]
+pub type ioctl_param_type = ::libc::c_int;
+
+mod consts {
+ use ::sys::ioctl::ioctl_num_type;
+ #[doc(hidden)]
+ pub const VOID: ioctl_num_type = 0x2000_0000;
+ #[doc(hidden)]
+ pub const OUT: ioctl_num_type = 0x4000_0000;
+ #[doc(hidden)]
+ pub const IN: ioctl_num_type = 0x8000_0000;
+ #[doc(hidden)]
+ pub const INOUT: ioctl_num_type = (IN|OUT);
+ #[doc(hidden)]
+ pub const IOCPARM_MASK: ioctl_num_type = 0x1fff;
+}
+
+pub use self::consts::*;
+
+#[macro_export]
+#[doc(hidden)]
+macro_rules! ioc {
+ ($inout:expr, $group:expr, $num:expr, $len:expr) => (
+ $inout | (($len as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::IOCPARM_MASK) << 16) | (($group as $crate::sys::ioctl::ioctl_num_type) << 8) | ($num as $crate::sys::ioctl::ioctl_num_type)
+ )
+}
+
+/// Generate an ioctl request code for a command that passes no data.
+///
+/// This is equivalent to the `_IO()` macro exposed by the C ioctl API.
+///
+/// You should only use this macro directly if the `ioctl` you're working
+/// with is "bad" and you cannot use `ioctl_none!()` directly.
+///
+/// # Example
+///
+/// ```
+/// # #[macro_use] extern crate nix;
+/// const KVMIO: u8 = 0xAE;
+/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03));
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! request_code_none {
+ ($g:expr, $n:expr) => (ioc!($crate::sys::ioctl::VOID, $g, $n, 0))
+}
+
+/// Generate an ioctl request code for a command that passes an integer
+///
+/// This is equivalent to the `_IOWINT()` macro exposed by the C ioctl API.
+///
+/// You should only use this macro directly if the `ioctl` you're working
+/// with is "bad" and you cannot use `ioctl_write_int!()` directly.
+#[macro_export]
+macro_rules! request_code_write_int {
+ ($g:expr, $n:expr) => (ioc!($crate::sys::ioctl::VOID, $g, $n, ::std::mem::size_of::<$crate::libc::c_int>()))
+}
+
+/// Generate an ioctl request code for a command that reads.
+///
+/// This is equivalent to the `_IOR()` macro exposed by the C ioctl API.
+///
+/// You should only use this macro directly if the `ioctl` you're working
+/// with is "bad" and you cannot use `ioctl_read!()` directly.
+///
+/// The read/write direction is relative to userland, so this
+/// command would be userland is reading and the kernel is
+/// writing.
+#[macro_export]
+macro_rules! request_code_read {
+ ($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::OUT, $g, $n, $len))
+}
+
+/// Generate an ioctl request code for a command that writes.
+///
+/// This is equivalent to the `_IOW()` macro exposed by the C ioctl API.
+///
+/// You should only use this macro directly if the `ioctl` you're working
+/// with is "bad" and you cannot use `ioctl_write!()` directly.
+///
+/// The read/write direction is relative to userland, so this
+/// command would be userland is writing and the kernel is
+/// reading.
+#[macro_export]
+macro_rules! request_code_write {
+ ($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::IN, $g, $n, $len))
+}
+
+/// Generate an ioctl request code for a command that reads and writes.
+///
+/// This is equivalent to the `_IOWR()` macro exposed by the C ioctl API.
+///
+/// You should only use this macro directly if the `ioctl` you're working
+/// with is "bad" and you cannot use `ioctl_readwrite!()` directly.
+#[macro_export]
+macro_rules! request_code_readwrite {
+ ($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::INOUT, $g, $n, $len))
+}
diff --git a/third_party/rust/nix/src/sys/ioctl/linux.rs b/third_party/rust/nix/src/sys/ioctl/linux.rs
new file mode 100644
index 0000000000..750a1c9832
--- /dev/null
+++ b/third_party/rust/nix/src/sys/ioctl/linux.rs
@@ -0,0 +1,140 @@
+/// The datatype used for the ioctl number
+#[cfg(any(target_os = "android", target_env = "musl"))]
+#[doc(hidden)]
+pub type ioctl_num_type = ::libc::c_int;
+#[cfg(not(any(target_os = "android", target_env = "musl")))]
+#[doc(hidden)]
+pub type ioctl_num_type = ::libc::c_ulong;
+/// The datatype used for the 3rd argument
+#[doc(hidden)]
+pub type ioctl_param_type = ::libc::c_ulong;
+
+#[doc(hidden)]
+pub const NRBITS: ioctl_num_type = 8;
+#[doc(hidden)]
+pub const TYPEBITS: ioctl_num_type = 8;
+
+#[cfg(any(target_arch = "mips", target_arch = "mips64", target_arch = "powerpc", target_arch = "powerpc64", target_arch = "sparc64"))]
+mod consts {
+ #[doc(hidden)]
+ pub const NONE: u8 = 1;
+ #[doc(hidden)]
+ pub const READ: u8 = 2;
+ #[doc(hidden)]
+ pub const WRITE: u8 = 4;
+ #[doc(hidden)]
+ pub const SIZEBITS: u8 = 13;
+ #[doc(hidden)]
+ pub const DIRBITS: u8 = 3;
+}
+
+// "Generic" ioctl protocol
+#[cfg(any(target_arch = "x86",
+ target_arch = "arm",
+ target_arch = "s390x",
+ target_arch = "x86_64",
+ target_arch = "aarch64"))]
+mod consts {
+ #[doc(hidden)]
+ pub const NONE: u8 = 0;
+ #[doc(hidden)]
+ pub const READ: u8 = 2;
+ #[doc(hidden)]
+ pub const WRITE: u8 = 1;
+ #[doc(hidden)]
+ pub const SIZEBITS: u8 = 14;
+ #[doc(hidden)]
+ pub const DIRBITS: u8 = 2;
+}
+
+pub use self::consts::*;
+
+#[doc(hidden)]
+pub const NRSHIFT: ioctl_num_type = 0;
+#[doc(hidden)]
+pub const TYPESHIFT: ioctl_num_type = NRSHIFT + NRBITS as ioctl_num_type;
+#[doc(hidden)]
+pub const SIZESHIFT: ioctl_num_type = TYPESHIFT + TYPEBITS as ioctl_num_type;
+#[doc(hidden)]
+pub const DIRSHIFT: ioctl_num_type = SIZESHIFT + SIZEBITS as ioctl_num_type;
+
+#[doc(hidden)]
+pub const NRMASK: ioctl_num_type = (1 << NRBITS) - 1;
+#[doc(hidden)]
+pub const TYPEMASK: ioctl_num_type = (1 << TYPEBITS) - 1;
+#[doc(hidden)]
+pub const SIZEMASK: ioctl_num_type = (1 << SIZEBITS) - 1;
+#[doc(hidden)]
+pub const DIRMASK: ioctl_num_type = (1 << DIRBITS) - 1;
+
+/// Encode an ioctl command.
+#[macro_export]
+#[doc(hidden)]
+macro_rules! ioc {
+ ($dir:expr, $ty:expr, $nr:expr, $sz:expr) => (
+ (($dir as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::DIRMASK) << $crate::sys::ioctl::DIRSHIFT) |
+ (($ty as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::TYPEMASK) << $crate::sys::ioctl::TYPESHIFT) |
+ (($nr as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::NRMASK) << $crate::sys::ioctl::NRSHIFT) |
+ (($sz as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::SIZEMASK) << $crate::sys::ioctl::SIZESHIFT))
+}
+
+/// Generate an ioctl request code for a command that passes no data.
+///
+/// This is equivalent to the `_IO()` macro exposed by the C ioctl API.
+///
+/// You should only use this macro directly if the `ioctl` you're working
+/// with is "bad" and you cannot use `ioctl_none!()` directly.
+///
+/// # Example
+///
+/// ```
+/// # #[macro_use] extern crate nix;
+/// const KVMIO: u8 = 0xAE;
+/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03));
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! request_code_none {
+ ($ty:expr, $nr:expr) => (ioc!($crate::sys::ioctl::NONE, $ty, $nr, 0))
+}
+
+/// Generate an ioctl request code for a command that reads.
+///
+/// This is equivalent to the `_IOR()` macro exposed by the C ioctl API.
+///
+/// You should only use this macro directly if the `ioctl` you're working
+/// with is "bad" and you cannot use `ioctl_read!()` directly.
+///
+/// The read/write direction is relative to userland, so this
+/// command would be userland is reading and the kernel is
+/// writing.
+#[macro_export]
+macro_rules! request_code_read {
+ ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::READ, $ty, $nr, $sz))
+}
+
+/// Generate an ioctl request code for a command that writes.
+///
+/// This is equivalent to the `_IOW()` macro exposed by the C ioctl API.
+///
+/// You should only use this macro directly if the `ioctl` you're working
+/// with is "bad" and you cannot use `ioctl_write!()` directly.
+///
+/// The read/write direction is relative to userland, so this
+/// command would be userland is writing and the kernel is
+/// reading.
+#[macro_export]
+macro_rules! request_code_write {
+ ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::WRITE, $ty, $nr, $sz))
+}
+
+/// Generate an ioctl request code for a command that reads and writes.
+///
+/// This is equivalent to the `_IOWR()` macro exposed by the C ioctl API.
+///
+/// You should only use this macro directly if the `ioctl` you're working
+/// with is "bad" and you cannot use `ioctl_readwrite!()` directly.
+#[macro_export]
+macro_rules! request_code_readwrite {
+ ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::READ | $crate::sys::ioctl::WRITE, $ty, $nr, $sz))
+}
diff --git a/third_party/rust/nix/src/sys/ioctl/mod.rs b/third_party/rust/nix/src/sys/ioctl/mod.rs
new file mode 100644
index 0000000000..35d508b131
--- /dev/null
+++ b/third_party/rust/nix/src/sys/ioctl/mod.rs
@@ -0,0 +1,778 @@
+//! Provide helpers for making ioctl system calls.
+//!
+//! This library is pretty low-level and messy. `ioctl` is not fun.
+//!
+//! What is an `ioctl`?
+//! ===================
+//!
+//! The `ioctl` syscall is the grab-bag syscall on POSIX systems. Don't want to add a new
+//! syscall? Make it an `ioctl`! `ioctl` refers to both the syscall, and the commands that can be
+//! sent with it. `ioctl` stands for "IO control", and the commands are always sent to a file
+//! descriptor.
+//!
+//! It is common to see `ioctl`s used for the following purposes:
+//!
+//! * Provide read/write access to out-of-band data related to a device such as configuration
+//! (for instance, setting serial port options)
+//! * Provide a mechanism for performing full-duplex data transfers (for instance, xfer on SPI
+//! devices).
+//! * Provide access to control functions on a device (for example, on Linux you can send
+//! commands like pause, resume, and eject to the CDROM device.
+//! * Do whatever else the device driver creator thought made most sense.
+//!
+//! `ioctl`s are synchronous system calls and are similar to read and write calls in that regard.
+//! They operate on file descriptors and have an identifier that specifies what the ioctl is.
+//! Additionally they may read or write data and therefore need to pass along a data pointer.
+//! Besides the semantics of the ioctls being confusing, the generation of this identifer can also
+//! be difficult.
+//!
+//! Historically `ioctl` numbers were arbitrary hard-coded values. In Linux (before 2.6) and some
+//! unices this has changed to a more-ordered system where the ioctl numbers are partitioned into
+//! subcomponents (For linux this is documented in
+//! [`Documentation/ioctl/ioctl-number.txt`](http://elixir.free-electrons.com/linux/latest/source/Documentation/ioctl/ioctl-number.txt)):
+//!
+//! * Number: The actual ioctl ID
+//! * Type: A grouping of ioctls for a common purpose or driver
+//! * Size: The size in bytes of the data that will be transferred
+//! * Direction: Whether there is any data and if it's read, write, or both
+//!
+//! Newer drivers should not generate complete integer identifiers for their `ioctl`s instead
+//! preferring to use the 4 components above to generate the final ioctl identifier. Because of
+//! how old `ioctl`s are, however, there are many hard-coded `ioctl` identifiers. These are
+//! commonly referred to as "bad" in `ioctl` documentation.
+//!
+//! Defining `ioctl`s
+//! =================
+//!
+//! This library provides several `ioctl_*!` macros for binding `ioctl`s. These generate public
+//! unsafe functions that can then be used for calling the ioctl. This macro has a few different
+//! ways it can be used depending on the specific ioctl you're working with.
+//!
+//! A simple `ioctl` is `SPI_IOC_RD_MODE`. This ioctl works with the SPI interface on Linux. This
+//! specific `ioctl` reads the mode of the SPI device as a `u8`. It's declared in
+//! `/include/uapi/linux/spi/spidev.h` as `_IOR(SPI_IOC_MAGIC, 1, __u8)`. Since it uses the `_IOR`
+//! macro, we know it's a `read` ioctl and can use the `ioctl_read!` macro as follows:
+//!
+//! ```
+//! # #[macro_use] extern crate nix;
+//! const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
+//! const SPI_IOC_TYPE_MODE: u8 = 1;
+//! ioctl_read!(spi_read_mode, SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, u8);
+//! # fn main() {}
+//! ```
+//!
+//! This generates the function:
+//!
+//! ```
+//! # #[macro_use] extern crate nix;
+//! # use std::mem;
+//! # use nix::{libc, Result};
+//! # use nix::errno::Errno;
+//! # use nix::libc::c_int as c_int;
+//! # const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
+//! # const SPI_IOC_TYPE_MODE: u8 = 1;
+//! pub unsafe fn spi_read_mode(fd: c_int, data: *mut u8) -> Result<c_int> {
+//! let res = libc::ioctl(fd, request_code_read!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, mem::size_of::<u8>()), data);
+//! Errno::result(res)
+//! }
+//! # fn main() {}
+//! ```
+//!
+//! The return value for the wrapper functions generated by the `ioctl_*!` macros are `nix::Error`s.
+//! These are generated by assuming the return value of the ioctl is `-1` on error and everything
+//! else is a valid return value. If this is not the case, `Result::map` can be used to map some
+//! of the range of "good" values (-Inf..-2, 0..Inf) into a smaller range in a helper function.
+//!
+//! Writing `ioctl`s generally use pointers as their data source and these should use the
+//! `ioctl_write_ptr!`. But in some cases an `int` is passed directly. For these `ioctl`s use the
+//! `ioctl_write_int!` macro. This variant does not take a type as the last argument:
+//!
+//! ```
+//! # #[macro_use] extern crate nix;
+//! const HCI_IOC_MAGIC: u8 = b'k';
+//! const HCI_IOC_HCIDEVUP: u8 = 1;
+//! ioctl_write_int!(hci_dev_up, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP);
+//! # fn main() {}
+//! ```
+//!
+//! Some `ioctl`s don't transfer any data, and those should use `ioctl_none!`. This macro
+//! doesn't take a type and so it is declared similar to the `write_int` variant shown above.
+//!
+//! The mode for a given `ioctl` should be clear from the documentation if it has good
+//! documentation. Otherwise it will be clear based on the macro used to generate the `ioctl`
+//! number where `_IO`, `_IOR`, `_IOW`, and `_IOWR` map to "none", "read", "write_*", and "readwrite"
+//! respectively. To determine the specific `write_` variant to use you'll need to find
+//! what the argument type is supposed to be. If it's an `int`, then `write_int` should be used,
+//! otherwise it should be a pointer and `write_ptr` should be used. On Linux the
+//! [`ioctl_list` man page](http://man7.org/linux/man-pages/man2/ioctl_list.2.html) describes a
+//! large number of `ioctl`s and describes their argument data type.
+//!
+//! Using "bad" `ioctl`s
+//! --------------------
+//!
+//! As mentioned earlier, there are many old `ioctl`s that do not use the newer method of
+//! generating `ioctl` numbers and instead use hardcoded values. These can be used with the
+//! `ioctl_*_bad!` macros. This naming comes from the Linux kernel which refers to these
+//! `ioctl`s as "bad". These are a different variant as they bypass calling the macro that generates
+//! the ioctl number and instead use the defined value directly.
+//!
+//! For example the `TCGETS` `ioctl` reads a `termios` data structure for a given file descriptor.
+//! It's defined as `0x5401` in `ioctls.h` on Linux and can be implemented as:
+//!
+//! ```
+//! # #[macro_use] extern crate nix;
+//! # #[cfg(any(target_os = "android", target_os = "linux"))]
+//! # use nix::libc::TCGETS as TCGETS;
+//! # #[cfg(any(target_os = "android", target_os = "linux"))]
+//! # use nix::libc::termios as termios;
+//! # #[cfg(any(target_os = "android", target_os = "linux"))]
+//! ioctl_read_bad!(tcgets, TCGETS, termios);
+//! # fn main() {}
+//! ```
+//!
+//! The generated function has the same form as that generated by `ioctl_read!`:
+//!
+//! ```text
+//! pub unsafe fn tcgets(fd: c_int, data: *mut termios) -> Result<c_int>;
+//! ```
+//!
+//! Working with Arrays
+//! -------------------
+//!
+//! Some `ioctl`s work with entire arrays of elements. These are supported by the `ioctl_*_buf`
+//! family of macros: `ioctl_read_buf`, `ioctl_write_buf`, and `ioctl_readwrite_buf`. Note that
+//! there are no "bad" versions for working with buffers. The generated functions include a `len`
+//! argument to specify the number of elements (where the type of each element is specified in the
+//! macro).
+//!
+//! Again looking to the SPI `ioctl`s on Linux for an example, there is a `SPI_IOC_MESSAGE` `ioctl`
+//! that queues up multiple SPI messages by writing an entire array of `spi_ioc_transfer` structs.
+//! `linux/spi/spidev.h` defines a macro to calculate the `ioctl` number like:
+//!
+//! ```C
+//! #define SPI_IOC_MAGIC 'k'
+//! #define SPI_MSGSIZE(N) ...
+//! #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
+//! ```
+//!
+//! The `SPI_MSGSIZE(N)` calculation is already handled by the `ioctl_*!` macros, so all that's
+//! needed to define this `ioctl` is:
+//!
+//! ```
+//! # #[macro_use] extern crate nix;
+//! const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
+//! const SPI_IOC_TYPE_MESSAGE: u8 = 0;
+//! # pub struct spi_ioc_transfer(u64);
+//! ioctl_write_buf!(spi_transfer, SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, spi_ioc_transfer);
+//! # fn main() {}
+//! ```
+//!
+//! This generates a function like:
+//!
+//! ```
+//! # #[macro_use] extern crate nix;
+//! # use std::mem;
+//! # use nix::{libc, Result};
+//! # use nix::errno::Errno;
+//! # use nix::libc::c_int as c_int;
+//! # const SPI_IOC_MAGIC: u8 = b'k';
+//! # const SPI_IOC_TYPE_MESSAGE: u8 = 0;
+//! # pub struct spi_ioc_transfer(u64);
+//! pub unsafe fn spi_message(fd: c_int, data: &mut [spi_ioc_transfer]) -> Result<c_int> {
+//! let res = libc::ioctl(fd,
+//! request_code_write!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, data.len() * mem::size_of::<spi_ioc_transfer>()),
+//! data);
+//! Errno::result(res)
+//! }
+//! # fn main() {}
+//! ```
+//!
+//! Finding `ioctl` Documentation
+//! -----------------------------
+//!
+//! For Linux, look at your system's headers. For example, `/usr/include/linux/input.h` has a lot
+//! of lines defining macros which use `_IO`, `_IOR`, `_IOW`, `_IOC`, and `_IOWR`. Some `ioctl`s are
+//! documented directly in the headers defining their constants, but others have more extensive
+//! documentation in man pages (like termios' `ioctl`s which are in `tty_ioctl(4)`).
+//!
+//! Documenting the Generated Functions
+//! ===================================
+//!
+//! In many cases, users will wish for the functions generated by the `ioctl`
+//! macro to be public and documented. For this reason, the generated functions
+//! are public by default. If you wish to hide the ioctl, you will need to put
+//! them in a private module.
+//!
+//! For documentation, it is possible to use doc comments inside the `ioctl_*!` macros. Here is an
+//! example :
+//!
+//! ```
+//! # #[macro_use] extern crate nix;
+//! # use nix::libc::c_int;
+//! ioctl_read! {
+//! /// Make the given terminal the controlling terminal of the calling process. The calling
+//! /// process must be a session leader and not have a controlling terminal already. If the
+//! /// terminal is already the controlling terminal of a different session group then the
+//! /// ioctl will fail with **EPERM**, unless the caller is root (more precisely: has the
+//! /// **CAP_SYS_ADMIN** capability) and arg equals 1, in which case the terminal is stolen
+//! /// and all processes that had it as controlling terminal lose it.
+//! tiocsctty, b't', 19, c_int
+//! }
+//!
+//! # fn main() {}
+//! ```
+#[cfg(any(target_os = "android", target_os = "linux"))]
+#[macro_use]
+mod linux;
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub use self::linux::*;
+
+#[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+#[macro_use]
+mod bsd;
+
+#[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+pub use self::bsd::*;
+
+/// Convert raw ioctl return value to a Nix result
+#[macro_export]
+#[doc(hidden)]
+macro_rules! convert_ioctl_res {
+ ($w:expr) => (
+ {
+ $crate::errno::Errno::result($w)
+ }
+ );
+}
+
+/// Generates a wrapper function for an ioctl that passes no data to the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl identifier
+/// * The ioctl sequence number
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+///
+/// # Example
+///
+/// The `videodev2` driver on Linux defines the `log_status` `ioctl` as:
+///
+/// ```C
+/// #define VIDIOC_LOG_STATUS _IO('V', 70)
+/// ```
+///
+/// This can be implemented in Rust like:
+///
+/// ```no_run
+/// # #[macro_use] extern crate nix;
+/// ioctl_none!(log_status, b'V', 70);
+/// fn main() {}
+/// ```
+#[macro_export]
+macro_rules! ioctl_none {
+ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => (
+ $(#[$attr])*
+ pub unsafe fn $name(fd: $crate::libc::c_int)
+ -> $crate::Result<$crate::libc::c_int> {
+ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_none!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type))
+ }
+ )
+}
+
+/// Generates a wrapper function for a "bad" ioctl that passes no data to the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl request code
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+///
+/// # Example
+///
+/// ```no_run
+/// # #[macro_use] extern crate nix;
+/// # extern crate libc;
+/// # use libc::TIOCNXCL;
+/// # use std::fs::File;
+/// # use std::os::unix::io::AsRawFd;
+/// ioctl_none_bad!(tiocnxcl, TIOCNXCL);
+/// fn main() {
+/// let file = File::open("/dev/ttyUSB0").unwrap();
+/// unsafe { tiocnxcl(file.as_raw_fd()) }.unwrap();
+/// }
+/// ```
+// TODO: add an example using request_code_*!()
+#[macro_export]
+macro_rules! ioctl_none_bad {
+ ($(#[$attr:meta])* $name:ident, $nr:expr) => (
+ $(#[$attr])*
+ pub unsafe fn $name(fd: $crate::libc::c_int)
+ -> $crate::Result<$crate::libc::c_int> {
+ convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type))
+ }
+ )
+}
+
+/// Generates a wrapper function for an ioctl that reads data from the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl identifier
+/// * The ioctl sequence number
+/// * The data type passed by this ioctl
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+///
+/// # Example
+///
+/// ```
+/// # #[macro_use] extern crate nix;
+/// const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
+/// const SPI_IOC_TYPE_MODE: u8 = 1;
+/// ioctl_read!(spi_read_mode, SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, u8);
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! ioctl_read {
+ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
+ $(#[$attr])*
+ pub unsafe fn $name(fd: $crate::libc::c_int,
+ data: *mut $ty)
+ -> $crate::Result<$crate::libc::c_int> {
+ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
+ }
+ )
+}
+
+/// Generates a wrapper function for a "bad" ioctl that reads data from the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl request code
+/// * The data type passed by this ioctl
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+///
+/// # Example
+///
+/// ```
+/// # extern crate libc;
+/// # #[macro_use] extern crate nix;
+/// # #[cfg(any(target_os = "android", target_os = "linux"))]
+/// ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios);
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! ioctl_read_bad {
+ ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => (
+ $(#[$attr])*
+ pub unsafe fn $name(fd: $crate::libc::c_int,
+ data: *mut $ty)
+ -> $crate::Result<$crate::libc::c_int> {
+ convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
+ }
+ )
+}
+
+/// Generates a wrapper function for an ioctl that writes data through a pointer to the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl identifier
+/// * The ioctl sequence number
+/// * The data type passed by this ioctl
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *const DATA_TYPE) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+///
+/// # Example
+///
+/// ```
+/// # #[macro_use] extern crate nix;
+/// # pub struct v4l2_audio {}
+/// ioctl_write_ptr!(s_audio, b'V', 34, v4l2_audio);
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! ioctl_write_ptr {
+ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
+ $(#[$attr])*
+ pub unsafe fn $name(fd: $crate::libc::c_int,
+ data: *const $ty)
+ -> $crate::Result<$crate::libc::c_int> {
+ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
+ }
+ )
+}
+
+/// Generates a wrapper function for a "bad" ioctl that writes data through a pointer to the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl request code
+/// * The data type passed by this ioctl
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *const DATA_TYPE) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+///
+/// # Example
+///
+/// ```
+/// # extern crate libc;
+/// # #[macro_use] extern crate nix;
+/// # #[cfg(any(target_os = "android", target_os = "linux"))]
+/// ioctl_write_ptr_bad!(tcsets, libc::TCSETS, libc::termios);
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! ioctl_write_ptr_bad {
+ ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => (
+ $(#[$attr])*
+ pub unsafe fn $name(fd: $crate::libc::c_int,
+ data: *const $ty)
+ -> $crate::Result<$crate::libc::c_int> {
+ convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
+ }
+ )
+}
+
+cfg_if!{
+ if #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] {
+ /// Generates a wrapper function for a ioctl that writes an integer to the kernel.
+ ///
+ /// The arguments to this macro are:
+ ///
+ /// * The function name
+ /// * The ioctl identifier
+ /// * The ioctl sequence number
+ ///
+ /// The generated function has the following signature:
+ ///
+ /// ```rust,ignore
+ /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: nix::sys::ioctl::ioctl_param_type) -> Result<libc::c_int>
+ /// ```
+ ///
+ /// `nix::sys::ioctl::ioctl_param_type` depends on the OS:
+ /// * BSD - `libc::c_int`
+ /// * Linux - `libc::c_ulong`
+ ///
+ /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # #[macro_use] extern crate nix;
+ /// ioctl_write_int!(vt_activate, b'v', 4);
+ /// # fn main() {}
+ /// ```
+ #[macro_export]
+ macro_rules! ioctl_write_int {
+ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => (
+ $(#[$attr])*
+ pub unsafe fn $name(fd: $crate::libc::c_int,
+ data: $crate::sys::ioctl::ioctl_param_type)
+ -> $crate::Result<$crate::libc::c_int> {
+ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write_int!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type, data))
+ }
+ )
+ }
+ } else {
+ /// Generates a wrapper function for a ioctl that writes an integer to the kernel.
+ ///
+ /// The arguments to this macro are:
+ ///
+ /// * The function name
+ /// * The ioctl identifier
+ /// * The ioctl sequence number
+ ///
+ /// The generated function has the following signature:
+ ///
+ /// ```rust,ignore
+ /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: nix::sys::ioctl::ioctl_param_type) -> Result<libc::c_int>
+ /// ```
+ ///
+ /// `nix::sys::ioctl::ioctl_param_type` depends on the OS:
+ /// * BSD - `libc::c_int`
+ /// * Linux - `libc::c_ulong`
+ ///
+ /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # #[macro_use] extern crate nix;
+ /// const HCI_IOC_MAGIC: u8 = b'k';
+ /// const HCI_IOC_HCIDEVUP: u8 = 1;
+ /// ioctl_write_int!(hci_dev_up, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP);
+ /// # fn main() {}
+ /// ```
+ #[macro_export]
+ macro_rules! ioctl_write_int {
+ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => (
+ $(#[$attr])*
+ pub unsafe fn $name(fd: $crate::libc::c_int,
+ data: $crate::sys::ioctl::ioctl_param_type)
+ -> $crate::Result<$crate::libc::c_int> {
+ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$crate::libc::c_int>()) as $crate::sys::ioctl::ioctl_num_type, data))
+ }
+ )
+ }
+ }
+}
+
+/// Generates a wrapper function for a "bad" ioctl that writes an integer to the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl request code
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: libc::c_int) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+///
+/// # Examples
+///
+/// ```
+/// # extern crate libc;
+/// # #[macro_use] extern crate nix;
+/// # #[cfg(any(target_os = "android", target_os = "linux"))]
+/// ioctl_write_int_bad!(tcsbrk, libc::TCSBRK);
+/// # fn main() {}
+/// ```
+///
+/// ```rust
+/// # #[macro_use] extern crate nix;
+/// const KVMIO: u8 = 0xAE;
+/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03));
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! ioctl_write_int_bad {
+ ($(#[$attr:meta])* $name:ident, $nr:expr) => (
+ $(#[$attr])*
+ pub unsafe fn $name(fd: $crate::libc::c_int,
+ data: $crate::libc::c_int)
+ -> $crate::Result<$crate::libc::c_int> {
+ convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
+ }
+ )
+}
+
+/// Generates a wrapper function for an ioctl that reads and writes data to the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl identifier
+/// * The ioctl sequence number
+/// * The data type passed by this ioctl
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+///
+/// # Example
+///
+/// ```
+/// # #[macro_use] extern crate nix;
+/// # pub struct v4l2_audio {}
+/// ioctl_readwrite!(enum_audio, b'V', 65, v4l2_audio);
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! ioctl_readwrite {
+ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
+ $(#[$attr])*
+ pub unsafe fn $name(fd: $crate::libc::c_int,
+ data: *mut $ty)
+ -> $crate::Result<$crate::libc::c_int> {
+ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
+ }
+ )
+}
+
+/// Generates a wrapper function for a "bad" ioctl that reads and writes data to the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl request code
+/// * The data type passed by this ioctl
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+// TODO: Find an example for ioctl_readwrite_bad
+#[macro_export]
+macro_rules! ioctl_readwrite_bad {
+ ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => (
+ $(#[$attr])*
+ pub unsafe fn $name(fd: $crate::libc::c_int,
+ data: *mut $ty)
+ -> $crate::Result<$crate::libc::c_int> {
+ convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
+ }
+ )
+}
+
+/// Generates a wrapper function for an ioctl that reads an array of elements from the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl identifier
+/// * The ioctl sequence number
+/// * The data type passed by this ioctl
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &mut [DATA_TYPE]) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+// TODO: Find an example for ioctl_read_buf
+#[macro_export]
+macro_rules! ioctl_read_buf {
+ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
+ $(#[$attr])*
+ pub unsafe fn $name(fd: $crate::libc::c_int,
+ data: &mut [$ty])
+ -> $crate::Result<$crate::libc::c_int> {
+ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
+ }
+ )
+}
+
+/// Generates a wrapper function for an ioctl that writes an array of elements to the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl identifier
+/// * The ioctl sequence number
+/// * The data type passed by this ioctl
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &[DATA_TYPE]) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+///
+/// # Examples
+///
+/// ```
+/// # #[macro_use] extern crate nix;
+/// const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
+/// const SPI_IOC_TYPE_MESSAGE: u8 = 0;
+/// # pub struct spi_ioc_transfer(u64);
+/// ioctl_write_buf!(spi_transfer, SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, spi_ioc_transfer);
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! ioctl_write_buf {
+ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
+ $(#[$attr])*
+ pub unsafe fn $name(fd: $crate::libc::c_int,
+ data: &[$ty])
+ -> $crate::Result<$crate::libc::c_int> {
+ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
+ }
+ )
+}
+
+/// Generates a wrapper function for an ioctl that reads and writes an array of elements to the kernel.
+///
+/// The arguments to this macro are:
+///
+/// * The function name
+/// * The ioctl identifier
+/// * The ioctl sequence number
+/// * The data type passed by this ioctl
+///
+/// The generated function has the following signature:
+///
+/// ```rust,ignore
+/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &mut [DATA_TYPE]) -> Result<libc::c_int>
+/// ```
+///
+/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
+// TODO: Find an example for readwrite_buf
+#[macro_export]
+macro_rules! ioctl_readwrite_buf {
+ ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
+ $(#[$attr])*
+ pub unsafe fn $name(fd: $crate::libc::c_int,
+ data: &mut [$ty])
+ -> $crate::Result<$crate::libc::c_int> {
+ convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
+ }
+ )
+}
diff --git a/third_party/rust/nix/src/sys/memfd.rs b/third_party/rust/nix/src/sys/memfd.rs
new file mode 100644
index 0000000000..9672429b31
--- /dev/null
+++ b/third_party/rust/nix/src/sys/memfd.rs
@@ -0,0 +1,20 @@
+use libc;
+use std::os::unix::io::RawFd;
+use Result;
+use errno::Errno;
+use std::ffi::CStr;
+
+libc_bitflags!(
+ pub struct MemFdCreateFlag: libc::c_uint {
+ MFD_CLOEXEC;
+ MFD_ALLOW_SEALING;
+ }
+);
+
+pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result<RawFd> {
+ let res = unsafe {
+ libc::syscall(libc::SYS_memfd_create, name.as_ptr(), flags.bits())
+ };
+
+ Errno::result(res).map(|r| r as RawFd)
+}
diff --git a/third_party/rust/nix/src/sys/mman.rs b/third_party/rust/nix/src/sys/mman.rs
new file mode 100644
index 0000000000..d6a28737c6
--- /dev/null
+++ b/third_party/rust/nix/src/sys/mman.rs
@@ -0,0 +1,296 @@
+use {Error, Result};
+#[cfg(not(target_os = "android"))]
+use NixPath;
+use errno::Errno;
+#[cfg(not(target_os = "android"))]
+use fcntl::OFlag;
+use libc::{self, c_int, c_void, size_t, off_t};
+#[cfg(not(target_os = "android"))]
+use sys::stat::Mode;
+use std::os::unix::io::RawFd;
+
+libc_bitflags!{
+ /// Desired memory protection of a memory mapping.
+ pub struct ProtFlags: c_int {
+ /// Pages cannot be accessed.
+ PROT_NONE;
+ /// Pages can be read.
+ PROT_READ;
+ /// Pages can be written.
+ PROT_WRITE;
+ /// Pages can be executed
+ PROT_EXEC;
+ /// Apply protection up to the end of a mapping that grows upwards.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ PROT_GROWSDOWN;
+ /// Apply protection down to the beginning of a mapping that grows downwards.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ PROT_GROWSUP;
+ }
+}
+
+libc_bitflags!{
+ /// Additional parameters for `mmap()`.
+ pub struct MapFlags: c_int {
+ /// Compatibility flag. Ignored.
+ MAP_FILE;
+ /// Share this mapping. Mutually exclusive with `MAP_PRIVATE`.
+ MAP_SHARED;
+ /// Create a private copy-on-write mapping. Mutually exclusive with `MAP_SHARED`.
+ MAP_PRIVATE;
+ /// Place the mapping at exactly the address specified in `addr`.
+ MAP_FIXED;
+ /// Synonym for `MAP_ANONYMOUS`.
+ MAP_ANON;
+ /// The mapping is not backed by any file.
+ #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))]
+ MAP_ANONYMOUS;
+ /// Put the mapping into the first 2GB of the process address space.
+ #[cfg(any(all(any(target_os = "android", target_os = "linux"),
+ any(target_arch = "x86", target_arch = "x86_64")),
+ all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "x86_64")),
+ all(target_os = "freebsd", target_pointer_width = "64")))]
+ MAP_32BIT;
+ /// Used for stacks; indicates to the kernel that the mapping should extend downward in memory.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ MAP_GROWSDOWN;
+ /// Compatibility flag. Ignored.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ MAP_DENYWRITE;
+ /// Compatibility flag. Ignored.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ MAP_EXECUTABLE;
+ /// Mark the mmaped region to be locked in the same way as `mlock(2)`.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ MAP_LOCKED;
+ /// Do not reserve swap space for this mapping.
+ ///
+ /// This was removed in FreeBSD 11.
+ #[cfg(not(target_os = "freebsd"))]
+ MAP_NORESERVE;
+ /// Populate page tables for a mapping.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ MAP_POPULATE;
+ /// Only meaningful when used with `MAP_POPULATE`. Don't perform read-ahead.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ MAP_NONBLOCK;
+ /// Allocate the mapping using "huge pages."
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ MAP_HUGETLB;
+ /// Lock the mapped region into memory as with `mlock(2)`.
+ #[cfg(target_os = "netbsd")]
+ MAP_WIRED;
+ /// Causes dirtied data in the specified range to be flushed to disk only when necessary.
+ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
+ MAP_NOSYNC;
+ /// Rename private pages to a file.
+ ///
+ /// This was removed in FreeBSD 11.
+ #[cfg(any(target_os = "dragonfly", target_os = "netbsd", target_os = "openbsd"))]
+ MAP_RENAME;
+ /// Region may contain semaphores.
+ #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
+ MAP_HASSEMAPHORE;
+ /// Region grows down, like a stack.
+ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
+ MAP_STACK;
+ /// Pages in this mapping are not retained in the kernel's memory cache.
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ MAP_NOCACHE;
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ MAP_JIT;
+ }
+}
+
+libc_enum!{
+ /// Usage information for a range of memory to allow for performance optimizations by the kernel.
+ ///
+ /// Used by [`madvise`](./fn.madvise.html).
+ #[repr(i32)]
+ pub enum MmapAdvise {
+ /// No further special treatment. This is the default.
+ MADV_NORMAL,
+ /// Expect random page references.
+ MADV_RANDOM,
+ /// Expect sequential page references.
+ MADV_SEQUENTIAL,
+ /// Expect access in the near future.
+ MADV_WILLNEED,
+ /// Do not expect access in the near future.
+ MADV_DONTNEED,
+ /// Free up a given range of pages and its associated backing store.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ MADV_REMOVE,
+ /// Do not make pages in this range available to the child after a `fork(2)`.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ MADV_DONTFORK,
+ /// Undo the effect of `MADV_DONTFORK`.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ MADV_DOFORK,
+ /// Poison the given pages.
+ ///
+ /// Subsequent references to those pages are treated like hardware memory corruption.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ MADV_HWPOISON,
+ /// Enable Kernel Samepage Merging (KSM) for the given pages.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ MADV_MERGEABLE,
+ /// Undo the effect of `MADV_MERGEABLE`
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ MADV_UNMERGEABLE,
+ /// Preserve the memory of each page but offline the original page.
+ #[cfg(any(target_os = "android",
+ all(target_os = "linux", any(
+ target_arch = "aarch64",
+ target_arch = "arm",
+ target_arch = "ppc",
+ target_arch = "s390x",
+ target_arch = "x86",
+ target_arch = "x86_64",
+ target_arch = "sparc64"))))]
+ MADV_SOFT_OFFLINE,
+ /// Enable Transparent Huge Pages (THP) for pages in the given range.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ MADV_HUGEPAGE,
+ /// Undo the effect of `MADV_HUGEPAGE`.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ MADV_NOHUGEPAGE,
+ /// Exclude the given range from a core dump.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ MADV_DONTDUMP,
+ /// Undo the effect of an earlier `MADV_DONTDUMP`.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ MADV_DODUMP,
+ /// Specify that the application no longer needs the pages in the given range.
+ MADV_FREE,
+ /// Request that the system not flush the current range to disk unless it needs to.
+ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
+ MADV_NOSYNC,
+ /// Undoes the effects of `MADV_NOSYNC` for any future pages dirtied within the given range.
+ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
+ MADV_AUTOSYNC,
+ /// Region is not included in a core file.
+ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
+ MADV_NOCORE,
+ /// Include region in a core file
+ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
+ MADV_CORE,
+ #[cfg(any(target_os = "freebsd"))]
+ MADV_PROTECT,
+ /// Invalidate the hardware page table for the given region.
+ #[cfg(target_os = "dragonfly")]
+ MADV_INVAL,
+ /// Set the offset of the page directory page to `value` for the virtual page table.
+ #[cfg(target_os = "dragonfly")]
+ MADV_SETMAP,
+ /// Indicates that the application will not need the data in the given range.
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ MADV_ZERO_WIRED_PAGES,
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ MADV_FREE_REUSABLE,
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ MADV_FREE_REUSE,
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ MADV_CAN_REUSE,
+ }
+}
+
+libc_bitflags!{
+ /// Configuration flags for `msync`.
+ pub struct MsFlags: c_int {
+ /// Schedule an update but return immediately.
+ MS_ASYNC;
+ /// Invalidate all cached data.
+ MS_INVALIDATE;
+ /// Invalidate pages, but leave them mapped.
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ MS_KILLPAGES;
+ /// Deactivate pages, but leave them mapped.
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ MS_DEACTIVATE;
+ /// Perform an update and wait for it to complete.
+ MS_SYNC;
+ }
+}
+
+libc_bitflags!{
+ /// Flags for `mlockall`.
+ pub struct MlockAllFlags: c_int {
+ /// Lock pages that are currently mapped into the address space of the process.
+ MCL_CURRENT;
+ /// Lock pages which will become mapped into the address space of the process in the future.
+ MCL_FUTURE;
+ }
+}
+
+/// Locks all memory pages that contain part of the address range with `length` bytes starting at
+/// `addr`. Locked pages never move to the swap area.
+pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> {
+ Errno::result(libc::mlock(addr, length)).map(drop)
+}
+
+/// Unlocks all memory pages that contain part of the address range with `length` bytes starting at
+/// `addr`.
+pub unsafe fn munlock(addr: *const c_void, length: size_t) -> Result<()> {
+ Errno::result(libc::munlock(addr, length)).map(drop)
+}
+
+/// Locks all memory pages mapped into this process' address space. Locked pages never move to the
+/// swap area.
+pub fn mlockall(flags: MlockAllFlags) -> Result<()> {
+ unsafe { Errno::result(libc::mlockall(flags.bits())) }.map(drop)
+}
+
+/// Unlocks all memory pages mapped into this process' address space.
+pub fn munlockall() -> Result<()> {
+ unsafe { Errno::result(libc::munlockall()) }.map(drop)
+}
+
+/// Calls to mmap are inherently unsafe, so they must be made in an unsafe block. Typically
+/// a higher-level abstraction will hide the unsafe interactions with the mmap'd region.
+pub unsafe fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: MapFlags, fd: RawFd, offset: off_t) -> Result<*mut c_void> {
+ let ret = libc::mmap(addr, length, prot.bits(), flags.bits(), fd, offset);
+
+ if ret == libc::MAP_FAILED {
+ Err(Error::Sys(Errno::last()))
+ } else {
+ Ok(ret)
+ }
+}
+
+pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> {
+ Errno::result(libc::munmap(addr, len)).map(drop)
+}
+
+pub unsafe fn madvise(addr: *mut c_void, length: size_t, advise: MmapAdvise) -> Result<()> {
+ Errno::result(libc::madvise(addr, length, advise as i32)).map(drop)
+}
+
+pub unsafe fn msync(addr: *mut c_void, length: size_t, flags: MsFlags) -> Result<()> {
+ Errno::result(libc::msync(addr, length, flags.bits())).map(drop)
+}
+
+#[cfg(not(target_os = "android"))]
+pub fn shm_open<P: ?Sized + NixPath>(name: &P, flag: OFlag, mode: Mode) -> Result<RawFd> {
+ let ret = name.with_nix_path(|cstr| {
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ unsafe {
+ libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::c_uint)
+ }
+ #[cfg(not(any(target_os = "macos", target_os = "ios")))]
+ unsafe {
+ libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::mode_t)
+ }
+ })?;
+
+ Errno::result(ret)
+}
+
+#[cfg(not(target_os = "android"))]
+pub fn shm_unlink<P: ?Sized + NixPath>(name: &P) -> Result<()> {
+ let ret = name.with_nix_path(|cstr| {
+ unsafe { libc::shm_unlink(cstr.as_ptr()) }
+ })?;
+
+ Errno::result(ret).map(drop)
+}
diff --git a/third_party/rust/nix/src/sys/mod.rs b/third_party/rust/nix/src/sys/mod.rs
new file mode 100644
index 0000000000..72d5964910
--- /dev/null
+++ b/third_party/rust/nix/src/sys/mod.rs
@@ -0,0 +1,90 @@
+#[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd"))]
+pub mod aio;
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub mod epoll;
+
+#[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+pub mod event;
+
+#[cfg(target_os = "linux")]
+pub mod eventfd;
+
+#[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+#[macro_use]
+pub mod ioctl;
+
+#[cfg(target_os = "linux")]
+pub mod memfd;
+
+pub mod mman;
+
+pub mod pthread;
+
+#[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+pub mod ptrace;
+
+#[cfg(target_os = "linux")]
+pub mod quota;
+
+#[cfg(any(target_os = "linux"))]
+pub mod reboot;
+
+pub mod select;
+
+#[cfg(any(target_os = "android",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+pub mod sendfile;
+
+pub mod signal;
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub mod signalfd;
+
+pub mod socket;
+
+pub mod stat;
+
+#[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
+pub mod statfs;
+
+pub mod statvfs;
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub mod sysinfo;
+
+pub mod termios;
+
+pub mod time;
+
+pub mod uio;
+
+pub mod utsname;
+
+pub mod wait;
diff --git a/third_party/rust/nix/src/sys/pthread.rs b/third_party/rust/nix/src/sys/pthread.rs
new file mode 100644
index 0000000000..a4d98250f2
--- /dev/null
+++ b/third_party/rust/nix/src/sys/pthread.rs
@@ -0,0 +1,13 @@
+use libc::{self, pthread_t};
+
+pub type Pthread = pthread_t;
+
+/// Obtain ID of the calling thread (see
+/// [`pthread_self(3)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_self.html)
+///
+/// The thread ID returned by `pthread_self()` is not the same thing as
+/// the kernel thread ID returned by a call to `gettid(2)`.
+#[inline]
+pub fn pthread_self() -> Pthread {
+ unsafe { libc::pthread_self() }
+}
diff --git a/third_party/rust/nix/src/sys/ptrace/bsd.rs b/third_party/rust/nix/src/sys/ptrace/bsd.rs
new file mode 100644
index 0000000000..7797d10647
--- /dev/null
+++ b/third_party/rust/nix/src/sys/ptrace/bsd.rs
@@ -0,0 +1,170 @@
+use errno::Errno;
+use libc::{self, c_int};
+use std::ptr;
+use sys::signal::Signal;
+use unistd::Pid;
+use Result;
+
+pub type RequestType = c_int;
+
+cfg_if! {
+ if #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "openbsd"))] {
+ #[doc(hidden)]
+ pub type AddressType = *mut ::libc::c_char;
+ } else {
+ #[doc(hidden)]
+ pub type AddressType = *mut ::libc::c_void;
+ }
+}
+
+libc_enum! {
+ #[repr(i32)]
+ /// Ptrace Request enum defining the action to be taken.
+ pub enum Request {
+ PT_TRACE_ME,
+ PT_READ_I,
+ PT_READ_D,
+ #[cfg(target_os = "macos")]
+ PT_READ_U,
+ PT_WRITE_I,
+ PT_WRITE_D,
+ #[cfg(target_os = "macos")]
+ PT_WRITE_U,
+ PT_CONTINUE,
+ PT_KILL,
+ #[cfg(any(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos"),
+ all(target_os = "openbsd", target_arch = "x86_64"),
+ all(target_os = "netbsd", any(target_arch = "x86_64",
+ target_arch = "powerpc"))))]
+ PT_STEP,
+ PT_ATTACH,
+ PT_DETACH,
+ #[cfg(target_os = "macos")]
+ PT_SIGEXC,
+ #[cfg(target_os = "macos")]
+ PT_THUPDATE,
+ #[cfg(target_os = "macos")]
+ PT_ATTACHEXC
+ }
+}
+
+unsafe fn ptrace_other(
+ request: Request,
+ pid: Pid,
+ addr: AddressType,
+ data: c_int,
+) -> Result<c_int> {
+ Errno::result(libc::ptrace(
+ request as RequestType,
+ libc::pid_t::from(pid),
+ addr,
+ data,
+ )).map(|_| 0)
+}
+
+/// Sets the process as traceable, as with `ptrace(PT_TRACEME, ...)`
+///
+/// Indicates that this process is to be traced by its parent.
+/// This is the only ptrace request to be issued by the tracee.
+pub fn traceme() -> Result<()> {
+ unsafe { ptrace_other(Request::PT_TRACE_ME, Pid::from_raw(0), ptr::null_mut(), 0).map(drop) }
+}
+
+/// Attach to a running process, as with `ptrace(PT_ATTACH, ...)`
+///
+/// Attaches to the process specified in pid, making it a tracee of the calling process.
+pub fn attach(pid: Pid) -> Result<()> {
+ unsafe { ptrace_other(Request::PT_ATTACH, pid, ptr::null_mut(), 0).map(drop) }
+}
+
+/// Detaches the current running process, as with `ptrace(PT_DETACH, ...)`
+///
+/// Detaches from the process specified in pid allowing it to run freely
+pub fn detach(pid: Pid) -> Result<()> {
+ unsafe { ptrace_other(Request::PT_DETACH, pid, ptr::null_mut(), 0).map(drop) }
+}
+
+/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)`
+///
+/// Continues the execution of the process with PID `pid`, optionally
+/// delivering a signal specified by `sig`.
+pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
+ let data = match sig.into() {
+ Some(s) => s as c_int,
+ None => 0,
+ };
+ unsafe {
+ // Ignore the useless return value
+ ptrace_other(Request::PT_CONTINUE, pid, 1 as AddressType, data).map(drop)
+ }
+}
+
+/// Issues a kill request as with `ptrace(PT_KILL, ...)`
+///
+/// This request is equivalent to `ptrace(PT_CONTINUE, ..., SIGKILL);`
+pub fn kill(pid: Pid) -> Result<()> {
+ unsafe {
+ ptrace_other(Request::PT_KILL, pid, 0 as AddressType, 0).map(drop)
+ }
+}
+
+/// Move the stopped tracee process forward by a single step as with
+/// `ptrace(PT_STEP, ...)`
+///
+/// Advances the execution of the process with PID `pid` by a single step optionally delivering a
+/// signal specified by `sig`.
+///
+/// # Example
+/// ```rust
+/// extern crate nix;
+/// use nix::sys::ptrace::step;
+/// use nix::unistd::Pid;
+/// use nix::sys::signal::Signal;
+/// use nix::sys::wait::*;
+/// fn main() {
+/// // If a process changes state to the stopped state because of a SIGUSR1
+/// // signal, this will step the process forward and forward the user
+/// // signal to the stopped process
+/// match waitpid(Pid::from_raw(-1), None) {
+/// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => {
+/// let _ = step(pid, Signal::SIGUSR1);
+/// }
+/// _ => {},
+/// }
+/// }
+/// ```
+#[cfg(
+ any(
+ any(target_os = "dragonfly", target_os = "freebsd", target_os = "macos"),
+ all(target_os = "openbsd", target_arch = "x86_64"),
+ all(target_os = "netbsd",
+ any(target_arch = "x86_64", target_arch = "powerpc")
+ )
+ )
+)]
+pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
+ let data = match sig.into() {
+ Some(s) => s as c_int,
+ None => 0,
+ };
+ unsafe { ptrace_other(Request::PT_STEP, pid, ptr::null_mut(), data).map(drop) }
+}
+
+/// Reads a word from a processes memory at the given address
+pub fn read(pid: Pid, addr: AddressType) -> Result<c_int> {
+ unsafe {
+ // Traditionally there was a difference between reading data or
+ // instruction memory but not in modern systems.
+ ptrace_other(Request::PT_READ_D, pid, addr, 0)
+ }
+}
+
+/// Writes a word into the processes memory at the given address
+pub fn write(pid: Pid, addr: AddressType, data: c_int) -> Result<()> {
+ unsafe { ptrace_other(Request::PT_WRITE_D, pid, addr, data).map(drop) }
+}
diff --git a/third_party/rust/nix/src/sys/ptrace/linux.rs b/third_party/rust/nix/src/sys/ptrace/linux.rs
new file mode 100644
index 0000000000..df15e66527
--- /dev/null
+++ b/third_party/rust/nix/src/sys/ptrace/linux.rs
@@ -0,0 +1,402 @@
+//! For detailed description of the ptrace requests, consult `man ptrace`.
+
+use std::{mem, ptr};
+use {Error, Result};
+use errno::Errno;
+use libc::{self, c_void, c_long, siginfo_t};
+use ::unistd::Pid;
+use sys::signal::Signal;
+
+pub type AddressType = *mut ::libc::c_void;
+
+#[cfg(all(target_os = "linux",
+ any(target_arch = "x86_64",
+ target_arch = "x86"),
+ target_env = "gnu"))]
+use libc::user_regs_struct;
+
+cfg_if! {
+ if #[cfg(any(all(target_os = "linux", target_arch = "s390x"),
+ all(target_os = "linux", target_env = "gnu")))] {
+ #[doc(hidden)]
+ pub type RequestType = ::libc::c_uint;
+ } else {
+ #[doc(hidden)]
+ pub type RequestType = ::libc::c_int;
+ }
+}
+
+libc_enum!{
+ #[cfg_attr(not(any(target_env = "musl", target_os = "android")), repr(u32))]
+ #[cfg_attr(any(target_env = "musl", target_os = "android"), repr(i32))]
+ /// Ptrace Request enum defining the action to be taken.
+ pub enum Request {
+ PTRACE_TRACEME,
+ PTRACE_PEEKTEXT,
+ PTRACE_PEEKDATA,
+ PTRACE_PEEKUSER,
+ PTRACE_POKETEXT,
+ PTRACE_POKEDATA,
+ PTRACE_POKEUSER,
+ PTRACE_CONT,
+ PTRACE_KILL,
+ PTRACE_SINGLESTEP,
+ #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
+ all(target_os = "linux", any(target_env = "musl",
+ target_arch = "mips",
+ target_arch = "mips64",
+ target_arch = "x86_64",
+ target_pointer_width = "32"))))]
+ PTRACE_GETREGS,
+ #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
+ all(target_os = "linux", any(target_env = "musl",
+ target_arch = "mips",
+ target_arch = "mips64",
+ target_arch = "x86_64",
+ target_pointer_width = "32"))))]
+ PTRACE_SETREGS,
+ #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
+ all(target_os = "linux", any(target_env = "musl",
+ target_arch = "mips",
+ target_arch = "mips64",
+ target_arch = "x86_64",
+ target_pointer_width = "32"))))]
+ PTRACE_GETFPREGS,
+ #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
+ all(target_os = "linux", any(target_env = "musl",
+ target_arch = "mips",
+ target_arch = "mips64",
+ target_arch = "x86_64",
+ target_pointer_width = "32"))))]
+ PTRACE_SETFPREGS,
+ PTRACE_ATTACH,
+ PTRACE_DETACH,
+ #[cfg(all(target_os = "linux", any(target_env = "musl",
+ target_arch = "mips",
+ target_arch = "mips64",
+ target_arch = "x86",
+ target_arch = "x86_64")))]
+ PTRACE_GETFPXREGS,
+ #[cfg(all(target_os = "linux", any(target_env = "musl",
+ target_arch = "mips",
+ target_arch = "mips64",
+ target_arch = "x86",
+ target_arch = "x86_64")))]
+ PTRACE_SETFPXREGS,
+ PTRACE_SYSCALL,
+ PTRACE_SETOPTIONS,
+ PTRACE_GETEVENTMSG,
+ PTRACE_GETSIGINFO,
+ PTRACE_SETSIGINFO,
+ #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
+ target_arch = "mips64"))))]
+ PTRACE_GETREGSET,
+ #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
+ target_arch = "mips64"))))]
+ PTRACE_SETREGSET,
+ #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
+ target_arch = "mips64"))))]
+ PTRACE_SEIZE,
+ #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
+ target_arch = "mips64"))))]
+ PTRACE_INTERRUPT,
+ #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
+ target_arch = "mips64"))))]
+ PTRACE_LISTEN,
+ #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
+ target_arch = "mips64"))))]
+ PTRACE_PEEKSIGINFO,
+ }
+}
+
+libc_enum!{
+ #[repr(i32)]
+ /// Using the ptrace options the tracer can configure the tracee to stop
+ /// at certain events. This enum is used to define those events as defined
+ /// in `man ptrace`.
+ pub enum Event {
+ /// Event that stops before a return from fork or clone.
+ PTRACE_EVENT_FORK,
+ /// Event that stops before a return from vfork or clone.
+ PTRACE_EVENT_VFORK,
+ /// Event that stops before a return from clone.
+ PTRACE_EVENT_CLONE,
+ /// Event that stops before a return from execve.
+ PTRACE_EVENT_EXEC,
+ /// Event for a return from vfork.
+ PTRACE_EVENT_VFORK_DONE,
+ /// Event for a stop before an exit. Unlike the waitpid Exit status program.
+ /// registers can still be examined
+ PTRACE_EVENT_EXIT,
+ /// STop triggered by a seccomp rule on a tracee.
+ PTRACE_EVENT_SECCOMP,
+ // PTRACE_EVENT_STOP not provided by libc because it's defined in glibc 2.26
+ }
+}
+
+libc_bitflags! {
+ /// Ptrace options used in conjunction with the PTRACE_SETOPTIONS request.
+ /// See `man ptrace` for more details.
+ pub struct Options: libc::c_int {
+ /// When delivering system call traps set a bit to allow tracer to
+ /// distinguish between normal stops or syscall stops. May not work on
+ /// all systems.
+ PTRACE_O_TRACESYSGOOD;
+ /// Stop tracee at next fork and start tracing the forked process.
+ PTRACE_O_TRACEFORK;
+ /// Stop tracee at next vfork call and trace the vforked process.
+ PTRACE_O_TRACEVFORK;
+ /// Stop tracee at next clone call and trace the cloned process.
+ PTRACE_O_TRACECLONE;
+ /// Stop tracee at next execve call.
+ PTRACE_O_TRACEEXEC;
+ /// Stop tracee at vfork completion.
+ PTRACE_O_TRACEVFORKDONE;
+ /// Stop tracee at next exit call. Stops before exit commences allowing
+ /// tracer to see location of exit and register states.
+ PTRACE_O_TRACEEXIT;
+ /// Stop tracee when a SECCOMP_RET_TRACE rule is triggered. See `man seccomp` for more
+ /// details.
+ PTRACE_O_TRACESECCOMP;
+ /// Send a SIGKILL to the tracee if the tracer exits. This is useful
+ /// for ptrace jailers to prevent tracees from escaping their control.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ PTRACE_O_EXITKILL;
+ }
+}
+
+/// Performs a ptrace request. If the request in question is provided by a specialised function
+/// this function will return an unsupported operation error.
+#[deprecated(
+ since="0.10.0",
+ note="usages of `ptrace()` should be replaced with the specialized helper functions instead"
+)]
+pub unsafe fn ptrace(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
+ use self::Request::*;
+ match request {
+ PTRACE_PEEKTEXT | PTRACE_PEEKDATA | PTRACE_GETSIGINFO |
+ PTRACE_GETEVENTMSG | PTRACE_SETSIGINFO | PTRACE_SETOPTIONS |
+ PTRACE_POKETEXT | PTRACE_POKEDATA | PTRACE_KILL => Err(Error::UnsupportedOperation),
+ _ => ptrace_other(request, pid, addr, data)
+ }
+}
+
+fn ptrace_peek(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
+ let ret = unsafe {
+ Errno::clear();
+ libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)
+ };
+ match Errno::result(ret) {
+ Ok(..) | Err(Error::Sys(Errno::UnknownErrno)) => Ok(ret),
+ err @ Err(..) => err,
+ }
+}
+
+/// Get user registers, as with `ptrace(PTRACE_GETREGS, ...)`
+#[cfg(all(target_os = "linux",
+ any(target_arch = "x86_64",
+ target_arch = "x86"),
+ target_env = "gnu"))]
+pub fn getregs(pid: Pid) -> Result<user_regs_struct> {
+ ptrace_get_data::<user_regs_struct>(Request::PTRACE_GETREGS, pid)
+}
+
+/// Set user registers, as with `ptrace(PTRACE_SETREGS, ...)`
+#[cfg(all(target_os = "linux",
+ any(target_arch = "x86_64",
+ target_arch = "x86"),
+ target_env = "gnu"))]
+pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
+ let res = unsafe {
+ libc::ptrace(Request::PTRACE_SETREGS as RequestType,
+ libc::pid_t::from(pid),
+ ptr::null_mut::<c_void>(),
+ &regs as *const _ as *const c_void)
+ };
+ Errno::result(res).map(drop)
+}
+
+/// Function for ptrace requests that return values from the data field.
+/// Some ptrace get requests populate structs or larger elements than `c_long`
+/// and therefore use the data field to return values. This function handles these
+/// requests.
+fn ptrace_get_data<T>(request: Request, pid: Pid) -> Result<T> {
+ // Creates an uninitialized pointer to store result in
+ let data: T = unsafe { mem::uninitialized() };
+ let res = unsafe {
+ libc::ptrace(request as RequestType,
+ libc::pid_t::from(pid),
+ ptr::null_mut::<T>(),
+ &data as *const _ as *const c_void)
+ };
+ Errno::result(res)?;
+ Ok(data)
+}
+
+unsafe fn ptrace_other(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
+ Errno::result(libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)).map(|_| 0)
+}
+
+/// Set options, as with `ptrace(PTRACE_SETOPTIONS,...)`.
+pub fn setoptions(pid: Pid, options: Options) -> Result<()> {
+ let res = unsafe {
+ libc::ptrace(Request::PTRACE_SETOPTIONS as RequestType,
+ libc::pid_t::from(pid),
+ ptr::null_mut::<c_void>(),
+ options.bits() as *mut c_void)
+ };
+ Errno::result(res).map(drop)
+}
+
+/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG,...)`
+pub fn getevent(pid: Pid) -> Result<c_long> {
+ ptrace_get_data::<c_long>(Request::PTRACE_GETEVENTMSG, pid)
+}
+
+/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO,...)`
+pub fn getsiginfo(pid: Pid) -> Result<siginfo_t> {
+ ptrace_get_data::<siginfo_t>(Request::PTRACE_GETSIGINFO, pid)
+}
+
+/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO,...)`
+pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> {
+ let ret = unsafe{
+ Errno::clear();
+ libc::ptrace(Request::PTRACE_SETSIGINFO as RequestType,
+ libc::pid_t::from(pid),
+ ptr::null_mut::<c_void>(),
+ sig as *const _ as *const c_void)
+ };
+ match Errno::result(ret) {
+ Ok(_) => Ok(()),
+ Err(e) => Err(e),
+ }
+}
+
+/// Sets the process as traceable, as with `ptrace(PTRACE_TRACEME, ...)`
+///
+/// Indicates that this process is to be traced by its parent.
+/// This is the only ptrace request to be issued by the tracee.
+pub fn traceme() -> Result<()> {
+ unsafe {
+ ptrace_other(
+ Request::PTRACE_TRACEME,
+ Pid::from_raw(0),
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ).map(drop) // ignore the useless return value
+ }
+}
+
+/// Ask for next syscall, as with `ptrace(PTRACE_SYSCALL, ...)`
+///
+/// Arranges for the tracee to be stopped at the next entry to or exit from a system call.
+pub fn syscall(pid: Pid) -> Result<()> {
+ unsafe {
+ ptrace_other(
+ Request::PTRACE_SYSCALL,
+ pid,
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ).map(drop) // ignore the useless return value
+ }
+}
+
+/// Attach to a running process, as with `ptrace(PTRACE_ATTACH, ...)`
+///
+/// Attaches to the process specified in pid, making it a tracee of the calling process.
+pub fn attach(pid: Pid) -> Result<()> {
+ unsafe {
+ ptrace_other(
+ Request::PTRACE_ATTACH,
+ pid,
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ).map(drop) // ignore the useless return value
+ }
+}
+
+/// Detaches the current running process, as with `ptrace(PTRACE_DETACH, ...)`
+///
+/// Detaches from the process specified in pid allowing it to run freely
+pub fn detach(pid: Pid) -> Result<()> {
+ unsafe {
+ ptrace_other(
+ Request::PTRACE_DETACH,
+ pid,
+ ptr::null_mut(),
+ ptr::null_mut()
+ ).map(drop)
+ }
+}
+
+/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)`
+///
+/// Continues the execution of the process with PID `pid`, optionally
+/// delivering a signal specified by `sig`.
+pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
+ let data = match sig.into() {
+ Some(s) => s as i32 as *mut c_void,
+ None => ptr::null_mut(),
+ };
+ unsafe {
+ ptrace_other(Request::PTRACE_CONT, pid, ptr::null_mut(), data).map(drop) // ignore the useless return value
+ }
+}
+
+/// Issues a kill request as with `ptrace(PTRACE_KILL, ...)`
+///
+/// This request is equivalent to `ptrace(PTRACE_CONT, ..., SIGKILL);`
+pub fn kill(pid: Pid) -> Result<()> {
+ unsafe {
+ ptrace_other(Request::PTRACE_KILL, pid, ptr::null_mut(), ptr::null_mut()).map(drop)
+ }
+}
+
+/// Move the stopped tracee process forward by a single step as with
+/// `ptrace(PTRACE_SINGLESTEP, ...)`
+///
+/// Advances the execution of the process with PID `pid` by a single step optionally delivering a
+/// signal specified by `sig`.
+///
+/// # Example
+/// ```rust
+/// extern crate nix;
+/// use nix::sys::ptrace::step;
+/// use nix::unistd::Pid;
+/// use nix::sys::signal::Signal;
+/// use nix::sys::wait::*;
+/// fn main() {
+/// // If a process changes state to the stopped state because of a SIGUSR1
+/// // signal, this will step the process forward and forward the user
+/// // signal to the stopped process
+/// match waitpid(Pid::from_raw(-1), None) {
+/// Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => {
+/// let _ = step(pid, Signal::SIGUSR1);
+/// }
+/// _ => {},
+/// }
+/// }
+/// ```
+pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
+ let data = match sig.into() {
+ Some(s) => s as i32 as *mut c_void,
+ None => ptr::null_mut(),
+ };
+ unsafe {
+ ptrace_other(Request::PTRACE_SINGLESTEP, pid, ptr::null_mut(), data).map(drop)
+ }
+}
+
+
+/// Reads a word from a processes memory at the given address
+pub fn read(pid: Pid, addr: AddressType) -> Result<c_long> {
+ ptrace_peek(Request::PTRACE_PEEKDATA, pid, addr, ptr::null_mut())
+}
+
+/// Writes a word into the processes memory at the given address
+pub fn write(pid: Pid, addr: AddressType, data: *mut c_void) -> Result<()> {
+ unsafe {
+ ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop)
+ }
+}
diff --git a/third_party/rust/nix/src/sys/ptrace/mod.rs b/third_party/rust/nix/src/sys/ptrace/mod.rs
new file mode 100644
index 0000000000..782c30409b
--- /dev/null
+++ b/third_party/rust/nix/src/sys/ptrace/mod.rs
@@ -0,0 +1,22 @@
+///! Provides helpers for making ptrace system calls
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+mod linux;
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub use self::linux::*;
+
+#[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+mod bsd;
+
+#[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"
+ ))]
+pub use self::bsd::*;
diff --git a/third_party/rust/nix/src/sys/quota.rs b/third_party/rust/nix/src/sys/quota.rs
new file mode 100644
index 0000000000..14c0462929
--- /dev/null
+++ b/third_party/rust/nix/src/sys/quota.rs
@@ -0,0 +1,274 @@
+//! Set and configure disk quotas for users, groups, or projects.
+//!
+//! # Examples
+//!
+//! Enabling and setting a quota:
+//!
+//! ```rust,no_run
+//! # use nix::sys::quota::{Dqblk, quotactl_on, quotactl_set, QuotaFmt, QuotaType, QuotaValidFlags};
+//! quotactl_on(QuotaType::USRQUOTA, "/dev/sda1", QuotaFmt::QFMT_VFS_V1, "aquota.user");
+//! let mut dqblk: Dqblk = Default::default();
+//! dqblk.set_blocks_hard_limit(10000);
+//! dqblk.set_blocks_soft_limit(8000);
+//! quotactl_set(QuotaType::USRQUOTA, "/dev/sda1", 50, &dqblk, QuotaValidFlags::QIF_BLIMITS);
+//! ```
+use std::default::Default;
+use std::{mem, ptr};
+use libc::{self, c_int, c_char};
+use {Result, NixPath};
+use errno::Errno;
+
+struct QuotaCmd(QuotaSubCmd, QuotaType);
+
+impl QuotaCmd {
+ fn as_int(&self) -> c_int {
+ unsafe { libc::QCMD(self.0 as i32, self.1 as i32) }
+ }
+}
+
+// linux quota version >= 2
+libc_enum!{
+ #[repr(i32)]
+ enum QuotaSubCmd {
+ Q_SYNC,
+ Q_QUOTAON,
+ Q_QUOTAOFF,
+ Q_GETQUOTA,
+ Q_SETQUOTA,
+ }
+}
+
+libc_enum!{
+ /// The scope of the quota.
+ #[repr(i32)]
+ pub enum QuotaType {
+ /// Specify a user quota
+ USRQUOTA,
+ /// Specify a group quota
+ GRPQUOTA,
+ }
+}
+
+libc_enum!{
+ /// The type of quota format to use.
+ #[repr(i32)]
+ pub enum QuotaFmt {
+ /// Use the original quota format.
+ QFMT_VFS_OLD,
+ /// Use the standard VFS v0 quota format.
+ ///
+ /// Handles 32-bit UIDs/GIDs and quota limits up to 2<sup>32</sup> bytes/2<sup>32</sup> inodes.
+ QFMT_VFS_V0,
+ /// Use the VFS v1 quota format.
+ ///
+ /// Handles 32-bit UIDs/GIDs and quota limits of 2<sup>64</sup> bytes/2<sup>64</sup> inodes.
+ QFMT_VFS_V1,
+ }
+}
+
+libc_bitflags!(
+ /// Indicates the quota fields that are valid to read from.
+ #[derive(Default)]
+ pub struct QuotaValidFlags: u32 {
+ /// The block hard & soft limit fields.
+ QIF_BLIMITS;
+ /// The current space field.
+ QIF_SPACE;
+ /// The inode hard & soft limit fields.
+ QIF_ILIMITS;
+ /// The current inodes field.
+ QIF_INODES;
+ /// The disk use time limit field.
+ QIF_BTIME;
+ /// The file quote time limit field.
+ QIF_ITIME;
+ /// All block & inode limits.
+ QIF_LIMITS;
+ /// The space & inodes usage fields.
+ QIF_USAGE;
+ /// The time limit fields.
+ QIF_TIMES;
+ /// All fields.
+ QIF_ALL;
+ }
+);
+
+/// Wrapper type for `if_dqblk`
+// FIXME: Change to repr(transparent)
+#[repr(C)]
+#[derive(Clone, Copy)]
+#[allow(missing_debug_implementations)]
+pub struct Dqblk(libc::dqblk);
+
+impl Default for Dqblk {
+ fn default() -> Dqblk {
+ Dqblk(libc::dqblk {
+ dqb_bhardlimit: 0,
+ dqb_bsoftlimit: 0,
+ dqb_curspace: 0,
+ dqb_ihardlimit: 0,
+ dqb_isoftlimit: 0,
+ dqb_curinodes: 0,
+ dqb_btime: 0,
+ dqb_itime: 0,
+ dqb_valid: 0,
+ })
+ }
+}
+
+impl Dqblk {
+ /// The absolute limit on disk quota blocks allocated.
+ pub fn blocks_hard_limit(&self) -> Option<u64> {
+ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
+ if valid_fields.contains(QuotaValidFlags::QIF_BLIMITS) {
+ Some(self.0.dqb_bhardlimit)
+ } else {
+ None
+ }
+ }
+
+ /// Set the absolute limit on disk quota blocks allocated.
+ pub fn set_blocks_hard_limit(&mut self, limit: u64) {
+ self.0.dqb_bhardlimit = limit;
+ }
+
+ /// Preferred limit on disk quota blocks
+ pub fn blocks_soft_limit(&self) -> Option<u64> {
+ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
+ if valid_fields.contains(QuotaValidFlags::QIF_BLIMITS) {
+ Some(self.0.dqb_bsoftlimit)
+ } else {
+ None
+ }
+ }
+
+ /// Set the preferred limit on disk quota blocks allocated.
+ pub fn set_blocks_soft_limit(&mut self, limit: u64) {
+ self.0.dqb_bsoftlimit = limit;
+ }
+
+ /// Current occupied space (bytes).
+ pub fn occupied_space(&self) -> Option<u64> {
+ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
+ if valid_fields.contains(QuotaValidFlags::QIF_SPACE) {
+ Some(self.0.dqb_curspace)
+ } else {
+ None
+ }
+ }
+
+ /// Maximum number of allocated inodes.
+ pub fn inodes_hard_limit(&self) -> Option<u64> {
+ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
+ if valid_fields.contains(QuotaValidFlags::QIF_ILIMITS) {
+ Some(self.0.dqb_ihardlimit)
+ } else {
+ None
+ }
+ }
+
+ /// Set the maximum number of allocated inodes.
+ pub fn set_inodes_hard_limit(&mut self, limit: u64) {
+ self.0.dqb_ihardlimit = limit;
+ }
+
+ /// Preferred inode limit
+ pub fn inodes_soft_limit(&self) -> Option<u64> {
+ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
+ if valid_fields.contains(QuotaValidFlags::QIF_ILIMITS) {
+ Some(self.0.dqb_isoftlimit)
+ } else {
+ None
+ }
+ }
+
+ /// Set the preferred limit of allocated inodes.
+ pub fn set_inodes_soft_limit(&mut self, limit: u64) {
+ self.0.dqb_isoftlimit = limit;
+ }
+
+ /// Current number of allocated inodes.
+ pub fn allocated_inodes(&self) -> Option<u64> {
+ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
+ if valid_fields.contains(QuotaValidFlags::QIF_INODES) {
+ Some(self.0.dqb_curinodes)
+ } else {
+ None
+ }
+ }
+
+ /// Time limit for excessive disk use.
+ pub fn block_time_limit(&self) -> Option<u64> {
+ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
+ if valid_fields.contains(QuotaValidFlags::QIF_BTIME) {
+ Some(self.0.dqb_btime)
+ } else {
+ None
+ }
+ }
+
+ /// Set the time limit for excessive disk use.
+ pub fn set_block_time_limit(&mut self, limit: u64) {
+ self.0.dqb_btime = limit;
+ }
+
+ /// Time limit for excessive files.
+ pub fn inode_time_limit(&self) -> Option<u64> {
+ let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
+ if valid_fields.contains(QuotaValidFlags::QIF_ITIME) {
+ Some(self.0.dqb_itime)
+ } else {
+ None
+ }
+ }
+
+ /// Set the time limit for excessive files.
+ pub fn set_inode_time_limit(&mut self, limit: u64) {
+ self.0.dqb_itime = limit;
+ }
+}
+
+fn quotactl<P: ?Sized + NixPath>(cmd: QuotaCmd, special: Option<&P>, id: c_int, addr: *mut c_char) -> Result<()> {
+ unsafe {
+ Errno::clear();
+ let res = match special {
+ Some(dev) => dev.with_nix_path(|path| libc::quotactl(cmd.as_int(), path.as_ptr(), id, addr)),
+ None => Ok(libc::quotactl(cmd.as_int(), ptr::null(), id, addr)),
+ }?;
+
+ Errno::result(res).map(drop)
+ }
+}
+
+/// Turn on disk quotas for a block device.
+pub fn quotactl_on<P: ?Sized + NixPath>(which: QuotaType, special: &P, format: QuotaFmt, quota_file: &P) -> Result<()> {
+ quota_file.with_nix_path(|path| {
+ let mut path_copy = path.to_bytes_with_nul().to_owned();
+ let p: *mut c_char = path_copy.as_mut_ptr() as *mut c_char;
+ quotactl(QuotaCmd(QuotaSubCmd::Q_QUOTAON, which), Some(special), format as c_int, p)
+ })?
+}
+
+/// Disable disk quotas for a block device.
+pub fn quotactl_off<P: ?Sized + NixPath>(which: QuotaType, special: &P) -> Result<()> {
+ quotactl(QuotaCmd(QuotaSubCmd::Q_QUOTAOFF, which), Some(special), 0, ptr::null_mut())
+}
+
+/// Update the on-disk copy of quota usages for a filesystem.
+pub fn quotactl_sync<P: ?Sized + NixPath>(which: QuotaType, special: Option<&P>) -> Result<()> {
+ quotactl(QuotaCmd(QuotaSubCmd::Q_SYNC, which), special, 0, ptr::null_mut())
+}
+
+/// Get disk quota limits and current usage for the given user/group id.
+pub fn quotactl_get<P: ?Sized + NixPath>(which: QuotaType, special: &P, id: c_int) -> Result<Dqblk> {
+ let mut dqblk = unsafe { mem::uninitialized() };
+ quotactl(QuotaCmd(QuotaSubCmd::Q_GETQUOTA, which), Some(special), id, &mut dqblk as *mut _ as *mut c_char)?;
+ dqblk
+}
+
+/// Configure quota values for the specified fields for a given user/group id.
+pub fn quotactl_set<P: ?Sized + NixPath>(which: QuotaType, special: &P, id: c_int, dqblk: &Dqblk, fields: QuotaValidFlags) -> Result<()> {
+ let mut dqblk_copy = *dqblk;
+ dqblk_copy.0.dqb_valid = fields.bits();
+ quotactl(QuotaCmd(QuotaSubCmd::Q_SETQUOTA, which), Some(special), id, &mut dqblk_copy as *mut _ as *mut c_char)
+}
diff --git a/third_party/rust/nix/src/sys/reboot.rs b/third_party/rust/nix/src/sys/reboot.rs
new file mode 100644
index 0000000000..bafa8fc119
--- /dev/null
+++ b/third_party/rust/nix/src/sys/reboot.rs
@@ -0,0 +1,45 @@
+//! Reboot/shutdown or enable/disable Ctrl-Alt-Delete.
+
+use {Error, Result};
+use errno::Errno;
+use libc;
+use void::Void;
+use std::mem::drop;
+
+libc_enum! {
+ /// How exactly should the system be rebooted.
+ ///
+ /// See [`set_cad_enabled()`](fn.set_cad_enabled.html) for
+ /// enabling/disabling Ctrl-Alt-Delete.
+ #[repr(i32)]
+ pub enum RebootMode {
+ RB_HALT_SYSTEM,
+ RB_KEXEC,
+ RB_POWER_OFF,
+ RB_AUTOBOOT,
+ // we do not support Restart2,
+ RB_SW_SUSPEND,
+ }
+}
+
+pub fn reboot(how: RebootMode) -> Result<Void> {
+ unsafe {
+ libc::reboot(how as libc::c_int)
+ };
+ Err(Error::Sys(Errno::last()))
+}
+
+/// Enable or disable the reboot keystroke (Ctrl-Alt-Delete).
+///
+/// Corresponds to calling `reboot(RB_ENABLE_CAD)` or `reboot(RB_DISABLE_CAD)` in C.
+pub fn set_cad_enabled(enable: bool) -> Result<()> {
+ let cmd = if enable {
+ libc::RB_ENABLE_CAD
+ } else {
+ libc::RB_DISABLE_CAD
+ };
+ let res = unsafe {
+ libc::reboot(cmd)
+ };
+ Errno::result(res).map(drop)
+}
diff --git a/third_party/rust/nix/src/sys/select.rs b/third_party/rust/nix/src/sys/select.rs
new file mode 100644
index 0000000000..95b6b148f6
--- /dev/null
+++ b/third_party/rust/nix/src/sys/select.rs
@@ -0,0 +1,335 @@
+use std::mem;
+use std::os::unix::io::RawFd;
+use std::ptr::{null, null_mut};
+use libc::{self, c_int};
+use Result;
+use errno::Errno;
+use sys::signal::SigSet;
+use sys::time::{TimeSpec, TimeVal};
+
+pub use libc::FD_SETSIZE;
+
+// FIXME: Change to repr(transparent) once it's stable
+#[repr(C)]
+#[derive(Clone, Copy)]
+#[allow(missing_debug_implementations)]
+pub struct FdSet(libc::fd_set);
+
+impl FdSet {
+ pub fn new() -> FdSet {
+ let mut fdset = unsafe { mem::uninitialized() };
+ unsafe { libc::FD_ZERO(&mut fdset) };
+ FdSet(fdset)
+ }
+
+ pub fn insert(&mut self, fd: RawFd) {
+ unsafe { libc::FD_SET(fd, &mut self.0) };
+ }
+
+ pub fn remove(&mut self, fd: RawFd) {
+ unsafe { libc::FD_CLR(fd, &mut self.0) };
+ }
+
+ pub fn contains(&mut self, fd: RawFd) -> bool {
+ unsafe { libc::FD_ISSET(fd, &mut self.0) }
+ }
+
+ pub fn clear(&mut self) {
+ unsafe { libc::FD_ZERO(&mut self.0) };
+ }
+
+ /// Finds the highest file descriptor in the set.
+ ///
+ /// Returns `None` if the set is empty.
+ ///
+ /// This can be used to calculate the `nfds` parameter of the [`select`] function.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # extern crate nix;
+ /// # use nix::sys::select::FdSet;
+ /// # fn main() {
+ /// let mut set = FdSet::new();
+ /// set.insert(4);
+ /// set.insert(9);
+ /// assert_eq!(set.highest(), Some(9));
+ /// # }
+ /// ```
+ ///
+ /// [`select`]: fn.select.html
+ pub fn highest(&mut self) -> Option<RawFd> {
+ for i in (0..FD_SETSIZE).rev() {
+ let i = i as RawFd;
+ if unsafe { libc::FD_ISSET(i, self as *mut _ as *mut libc::fd_set) } {
+ return Some(i)
+ }
+ }
+
+ None
+ }
+}
+
+/// Monitors file descriptors for readiness
+///
+/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all
+/// file descriptors that are ready for the given operation are set.
+///
+/// When this function returns, `timeout` has an implementation-defined value.
+///
+/// # Parameters
+///
+/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this
+/// is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1
+/// to the maximum of that.
+/// * `readfds`: File descriptors to check for being ready to read.
+/// * `writefds`: File descriptors to check for being ready to write.
+/// * `errorfds`: File descriptors to check for pending error conditions.
+/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block
+/// indefinitely).
+///
+/// # References
+///
+/// [select(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html)
+///
+/// [`FdSet::highest`]: struct.FdSet.html#method.highest
+pub fn select<'a, N, R, W, E, T>(nfds: N,
+ readfds: R,
+ writefds: W,
+ errorfds: E,
+ timeout: T) -> Result<c_int>
+where
+ N: Into<Option<c_int>>,
+ R: Into<Option<&'a mut FdSet>>,
+ W: Into<Option<&'a mut FdSet>>,
+ E: Into<Option<&'a mut FdSet>>,
+ T: Into<Option<&'a mut TimeVal>>,
+{
+ let mut readfds = readfds.into();
+ let mut writefds = writefds.into();
+ let mut errorfds = errorfds.into();
+ let timeout = timeout.into();
+
+ let nfds = nfds.into().unwrap_or_else(|| {
+ readfds.iter_mut()
+ .chain(writefds.iter_mut())
+ .chain(errorfds.iter_mut())
+ .map(|set| set.highest().unwrap_or(-1))
+ .max()
+ .unwrap_or(-1) + 1
+ });
+
+ let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
+ let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
+ let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
+ let timeout = timeout.map(|tv| tv as *mut _ as *mut libc::timeval)
+ .unwrap_or(null_mut());
+
+ let res = unsafe {
+ libc::select(nfds, readfds, writefds, errorfds, timeout)
+ };
+
+ Errno::result(res)
+}
+
+/// Monitors file descriptors for readiness with an altered signal mask.
+///
+/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all
+/// file descriptors that are ready for the given operation are set.
+///
+/// When this function returns, the original signal mask is restored.
+///
+/// Unlike [`select`](#fn.select), `pselect` does not mutate the `timeout` value.
+///
+/// # Parameters
+///
+/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this
+/// is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1
+/// to the maximum of that.
+/// * `readfds`: File descriptors to check for read readiness
+/// * `writefds`: File descriptors to check for write readiness
+/// * `errorfds`: File descriptors to check for pending error conditions.
+/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block
+/// indefinitely).
+/// * `sigmask`: Signal mask to activate while waiting for file descriptors to turn
+/// ready (`None` to set no alternative signal mask).
+///
+/// # References
+///
+/// [pselect(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pselect.html)
+///
+/// [The new pselect() system call](https://lwn.net/Articles/176911/)
+///
+/// [`FdSet::highest`]: struct.FdSet.html#method.highest
+pub fn pselect<'a, N, R, W, E, T, S>(nfds: N,
+ readfds: R,
+ writefds: W,
+ errorfds: E,
+ timeout: T,
+ sigmask: S) -> Result<c_int>
+where
+ N: Into<Option<c_int>>,
+ R: Into<Option<&'a mut FdSet>>,
+ W: Into<Option<&'a mut FdSet>>,
+ E: Into<Option<&'a mut FdSet>>,
+ T: Into<Option<&'a TimeSpec>>,
+ S: Into<Option<&'a SigSet>>,
+{
+ let mut readfds = readfds.into();
+ let mut writefds = writefds.into();
+ let mut errorfds = errorfds.into();
+ let sigmask = sigmask.into();
+ let timeout = timeout.into();
+
+ let nfds = nfds.into().unwrap_or_else(|| {
+ readfds.iter_mut()
+ .chain(writefds.iter_mut())
+ .chain(errorfds.iter_mut())
+ .map(|set| set.highest().unwrap_or(-1))
+ .max()
+ .unwrap_or(-1) + 1
+ });
+
+ let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
+ let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
+ let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
+ let timeout = timeout.map(|ts| ts.as_ref() as *const libc::timespec).unwrap_or(null());
+ let sigmask = sigmask.map(|sm| sm.as_ref() as *const libc::sigset_t).unwrap_or(null());
+
+ let res = unsafe {
+ libc::pselect(nfds, readfds, writefds, errorfds, timeout, sigmask)
+ };
+
+ Errno::result(res)
+}
+
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use std::os::unix::io::RawFd;
+ use sys::time::{TimeVal, TimeValLike};
+ use unistd::{write, pipe};
+
+ #[test]
+ fn fdset_insert() {
+ let mut fd_set = FdSet::new();
+
+ for i in 0..FD_SETSIZE {
+ assert!(!fd_set.contains(i as RawFd));
+ }
+
+ fd_set.insert(7);
+
+ assert!(fd_set.contains(7));
+ }
+
+ #[test]
+ fn fdset_remove() {
+ let mut fd_set = FdSet::new();
+
+ for i in 0..FD_SETSIZE {
+ assert!(!fd_set.contains(i as RawFd));
+ }
+
+ fd_set.insert(7);
+ fd_set.remove(7);
+
+ for i in 0..FD_SETSIZE {
+ assert!(!fd_set.contains(i as RawFd));
+ }
+ }
+
+ #[test]
+ fn fdset_clear() {
+ let mut fd_set = FdSet::new();
+ fd_set.insert(1);
+ fd_set.insert((FD_SETSIZE / 2) as RawFd);
+ fd_set.insert((FD_SETSIZE - 1) as RawFd);
+
+ fd_set.clear();
+
+ for i in 0..FD_SETSIZE {
+ assert!(!fd_set.contains(i as RawFd));
+ }
+ }
+
+ #[test]
+ fn fdset_highest() {
+ let mut set = FdSet::new();
+ assert_eq!(set.highest(), None);
+ set.insert(0);
+ assert_eq!(set.highest(), Some(0));
+ set.insert(90);
+ assert_eq!(set.highest(), Some(90));
+ set.remove(0);
+ assert_eq!(set.highest(), Some(90));
+ set.remove(90);
+ assert_eq!(set.highest(), None);
+
+ set.insert(4);
+ set.insert(5);
+ set.insert(7);
+ assert_eq!(set.highest(), Some(7));
+ }
+
+ #[test]
+ fn test_select() {
+ let (r1, w1) = pipe().unwrap();
+ write(w1, b"hi!").unwrap();
+ let (r2, _w2) = pipe().unwrap();
+
+ let mut fd_set = FdSet::new();
+ fd_set.insert(r1);
+ fd_set.insert(r2);
+
+ let mut timeout = TimeVal::seconds(10);
+ assert_eq!(1, select(None,
+ &mut fd_set,
+ None,
+ None,
+ &mut timeout).unwrap());
+ assert!(fd_set.contains(r1));
+ assert!(!fd_set.contains(r2));
+ }
+
+ #[test]
+ fn test_select_nfds() {
+ let (r1, w1) = pipe().unwrap();
+ write(w1, b"hi!").unwrap();
+ let (r2, _w2) = pipe().unwrap();
+
+ let mut fd_set = FdSet::new();
+ fd_set.insert(r1);
+ fd_set.insert(r2);
+
+ let mut timeout = TimeVal::seconds(10);
+ assert_eq!(1, select(Some(fd_set.highest().unwrap() + 1),
+ &mut fd_set,
+ None,
+ None,
+ &mut timeout).unwrap());
+ assert!(fd_set.contains(r1));
+ assert!(!fd_set.contains(r2));
+ }
+
+ #[test]
+ fn test_select_nfds2() {
+ let (r1, w1) = pipe().unwrap();
+ write(w1, b"hi!").unwrap();
+ let (r2, _w2) = pipe().unwrap();
+
+ let mut fd_set = FdSet::new();
+ fd_set.insert(r1);
+ fd_set.insert(r2);
+
+ let mut timeout = TimeVal::seconds(10);
+ assert_eq!(1, select(::std::cmp::max(r1, r2) + 1,
+ &mut fd_set,
+ None,
+ None,
+ &mut timeout).unwrap());
+ assert!(fd_set.contains(r1));
+ assert!(!fd_set.contains(r2));
+ }
+}
diff --git a/third_party/rust/nix/src/sys/sendfile.rs b/third_party/rust/nix/src/sys/sendfile.rs
new file mode 100644
index 0000000000..1190518d8b
--- /dev/null
+++ b/third_party/rust/nix/src/sys/sendfile.rs
@@ -0,0 +1,200 @@
+use std::os::unix::io::RawFd;
+use std::ptr;
+
+use libc::{self, off_t};
+
+use Result;
+use errno::Errno;
+
+/// Copy up to `count` bytes to `out_fd` from `in_fd` starting at `offset`.
+///
+/// Returns a `Result` with the number of bytes written.
+///
+/// If `offset` is `None`, `sendfile` will begin reading at the current offset of `in_fd`and will
+/// update the offset of `in_fd`. If `offset` is `Some`, `sendfile` will begin at the specified
+/// offset and will not update the offset of `in_fd`. Instead, it will mutate `offset` to point to
+/// the byte after the last byte copied.
+///
+/// `in_fd` must support `mmap`-like operations and therefore cannot be a socket.
+///
+/// For more information, see [the sendfile(2) man page.](http://man7.org/linux/man-pages/man2/sendfile.2.html)
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub fn sendfile(
+ out_fd: RawFd,
+ in_fd: RawFd,
+ offset: Option<&mut off_t>,
+ count: usize,
+) -> Result<usize> {
+ let offset = offset
+ .map(|offset| offset as *mut _)
+ .unwrap_or(ptr::null_mut());
+ let ret = unsafe { libc::sendfile(out_fd, in_fd, offset, count) };
+ Errno::result(ret).map(|r| r as usize)
+}
+
+cfg_if! {
+ if #[cfg(any(target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos"))] {
+ use sys::uio::IoVec;
+
+ #[allow(missing_debug_implementations)]
+ struct SendfileHeaderTrailer<'a>(
+ libc::sf_hdtr,
+ Option<Vec<IoVec<&'a [u8]>>>,
+ Option<Vec<IoVec<&'a [u8]>>>,
+ );
+
+ impl<'a> SendfileHeaderTrailer<'a> {
+ fn new(
+ headers: Option<&'a [&'a [u8]]>,
+ trailers: Option<&'a [&'a [u8]]>
+ ) -> SendfileHeaderTrailer<'a> {
+ let header_iovecs: Option<Vec<IoVec<&[u8]>>> =
+ headers.map(|s| s.iter().map(|b| IoVec::from_slice(b)).collect());
+ let trailer_iovecs: Option<Vec<IoVec<&[u8]>>> =
+ trailers.map(|s| s.iter().map(|b| IoVec::from_slice(b)).collect());
+ SendfileHeaderTrailer(
+ libc::sf_hdtr {
+ headers: {
+ header_iovecs
+ .as_ref()
+ .map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec
+ },
+ hdr_cnt: header_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32,
+ trailers: {
+ trailer_iovecs
+ .as_ref()
+ .map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec
+ },
+ trl_cnt: trailer_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32
+ },
+ header_iovecs,
+ trailer_iovecs,
+ )
+ }
+ }
+ }
+}
+
+cfg_if! {
+ if #[cfg(target_os = "freebsd")] {
+ use libc::c_int;
+
+ libc_bitflags!{
+ /// Configuration options for [`sendfile`.](fn.sendfile.html)
+ pub struct SfFlags: c_int {
+ /// Causes `sendfile` to return EBUSY instead of blocking when attempting to read a
+ /// busy page.
+ SF_NODISKIO;
+ /// Causes `sendfile` to sleep until the network stack releases its reference to the
+ /// VM pages read. When `sendfile` returns, the data is not guaranteed to have been
+ /// sent, but it is safe to modify the file.
+ SF_SYNC;
+ /// Causes `sendfile` to cache exactly the number of pages specified in the
+ /// `readahead` parameter, disabling caching heuristics.
+ SF_USER_READAHEAD;
+ /// Causes `sendfile` not to cache the data read.
+ SF_NOCACHE;
+ }
+ }
+
+ /// Read up to `count` bytes from `in_fd` starting at `offset` and write to `out_sock`.
+ ///
+ /// Returns a `Result` and a count of bytes written. Bytes written may be non-zero even if
+ /// an error occurs.
+ ///
+ /// `in_fd` must describe a regular file or shared memory object. `out_sock` must describe a
+ /// stream socket.
+ ///
+ /// If `offset` falls past the end of the file, the function returns success and zero bytes
+ /// written.
+ ///
+ /// If `count` is `None` or 0, bytes will be read from `in_fd` until reaching the end of
+ /// file (EOF).
+ ///
+ /// `headers` and `trailers` specify optional slices of byte slices to be sent before and
+ /// after the data read from `in_fd`, respectively. The length of headers and trailers sent
+ /// is included in the returned count of bytes written. The values of `offset` and `count`
+ /// do not apply to headers or trailers.
+ ///
+ /// `readahead` specifies the minimum number of pages to cache in memory ahead of the page
+ /// currently being sent.
+ ///
+ /// For more information, see
+ /// [the sendfile(2) man page.](https://www.freebsd.org/cgi/man.cgi?query=sendfile&sektion=2)
+ pub fn sendfile(
+ in_fd: RawFd,
+ out_sock: RawFd,
+ offset: off_t,
+ count: Option<usize>,
+ headers: Option<&[&[u8]]>,
+ trailers: Option<&[&[u8]]>,
+ flags: SfFlags,
+ readahead: u16
+ ) -> (Result<()>, off_t) {
+ // Readahead goes in upper 16 bits
+ // Flags goes in lower 16 bits
+ // see `man 2 sendfile`
+ let flags: u32 = ((readahead as u32) << 16) | (flags.bits() as u32);
+ let mut bytes_sent: off_t = 0;
+ let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
+ let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr);
+ let return_code = unsafe {
+ libc::sendfile(in_fd,
+ out_sock,
+ offset,
+ count.unwrap_or(0),
+ hdtr_ptr as *mut libc::sf_hdtr,
+ &mut bytes_sent as *mut off_t,
+ flags as c_int)
+ };
+ (Errno::result(return_code).and(Ok(())), bytes_sent)
+ }
+ } else if #[cfg(any(target_os = "ios", target_os = "macos"))] {
+ /// Read bytes from `in_fd` starting at `offset` and write up to `count` bytes to
+ /// `out_sock`.
+ ///
+ /// Returns a `Result` and a count of bytes written. Bytes written may be non-zero even if
+ /// an error occurs.
+ ///
+ /// `in_fd` must describe a regular file. `out_sock` must describe a stream socket.
+ ///
+ /// If `offset` falls past the end of the file, the function returns success and zero bytes
+ /// written.
+ ///
+ /// If `count` is `None` or 0, bytes will be read from `in_fd` until reaching the end of
+ /// file (EOF).
+ ///
+ /// `hdtr` specifies an optional list of headers and trailers to be sent before and after
+ /// the data read from `in_fd`, respectively. The length of headers and trailers sent is
+ /// included in the returned count of bytes written. If any headers are specified and
+ /// `count` is non-zero, the length of the headers will be counted in the limit of total
+ /// bytes sent. Trailers do not count toward the limit of bytes sent and will always be sent
+ /// regardless. The value of `offset` does not affect headers or trailers.
+ ///
+ /// For more information, see
+ /// [the sendfile(2) man page.](https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man2/sendfile.2.html)
+ pub fn sendfile(
+ in_fd: RawFd,
+ out_sock: RawFd,
+ offset: off_t,
+ count: Option<off_t>,
+ headers: Option<&[&[u8]]>,
+ trailers: Option<&[&[u8]]>
+ ) -> (Result<()>, off_t) {
+ let mut len = count.unwrap_or(0);
+ let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
+ let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr);
+ let return_code = unsafe {
+ libc::sendfile(in_fd,
+ out_sock,
+ offset,
+ &mut len as *mut off_t,
+ hdtr_ptr as *mut libc::sf_hdtr,
+ 0)
+ };
+ (Errno::result(return_code).and(Ok(())), len)
+ }
+ }
+}
diff --git a/third_party/rust/nix/src/sys/signal.rs b/third_party/rust/nix/src/sys/signal.rs
new file mode 100644
index 0000000000..cd86723e04
--- /dev/null
+++ b/third_party/rust/nix/src/sys/signal.rs
@@ -0,0 +1,984 @@
+// Portions of this file are Copyright 2014 The Rust Project Developers.
+// See http://rust-lang.org/COPYRIGHT.
+
+///! Operating system signals.
+
+use libc;
+use {Error, Result};
+use errno::Errno;
+use std::mem;
+use std::fmt;
+use std::str::FromStr;
+#[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::*;
+
+libc_enum!{
+ // 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
+ // this is not (yet) possible.
+ #[repr(i32)]
+ pub enum Signal {
+ SIGHUP,
+ SIGINT,
+ SIGQUIT,
+ SIGILL,
+ SIGTRAP,
+ SIGABRT,
+ SIGBUS,
+ SIGFPE,
+ SIGKILL,
+ SIGUSR1,
+ SIGSEGV,
+ SIGUSR2,
+ SIGPIPE,
+ SIGALRM,
+ SIGTERM,
+ #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
+ not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
+ SIGSTKFLT,
+ SIGCHLD,
+ SIGCONT,
+ SIGSTOP,
+ SIGTSTP,
+ SIGTTIN,
+ SIGTTOU,
+ SIGURG,
+ SIGXCPU,
+ SIGXFSZ,
+ SIGVTALRM,
+ SIGPROF,
+ SIGWINCH,
+ SIGIO,
+ #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
+ SIGPWR,
+ SIGSYS,
+ #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
+ SIGEMT,
+ #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
+ SIGINFO,
+ }
+}
+
+impl FromStr for Signal {
+ type Err = Error;
+ fn from_str(s: &str) -> Result<Signal> {
+ Ok(match s {
+ "SIGHUP" => Signal::SIGHUP,
+ "SIGINT" => Signal::SIGINT,
+ "SIGQUIT" => Signal::SIGQUIT,
+ "SIGILL" => Signal::SIGILL,
+ "SIGTRAP" => Signal::SIGTRAP,
+ "SIGABRT" => Signal::SIGABRT,
+ "SIGBUS" => Signal::SIGBUS,
+ "SIGFPE" => Signal::SIGFPE,
+ "SIGKILL" => Signal::SIGKILL,
+ "SIGUSR1" => Signal::SIGUSR1,
+ "SIGSEGV" => Signal::SIGSEGV,
+ "SIGUSR2" => Signal::SIGUSR2,
+ "SIGPIPE" => Signal::SIGPIPE,
+ "SIGALRM" => Signal::SIGALRM,
+ "SIGTERM" => Signal::SIGTERM,
+ #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
+ not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
+ "SIGSTKFLT" => Signal::SIGSTKFLT,
+ "SIGCHLD" => Signal::SIGCHLD,
+ "SIGCONT" => Signal::SIGCONT,
+ "SIGSTOP" => Signal::SIGSTOP,
+ "SIGTSTP" => Signal::SIGTSTP,
+ "SIGTTIN" => Signal::SIGTTIN,
+ "SIGTTOU" => Signal::SIGTTOU,
+ "SIGURG" => Signal::SIGURG,
+ "SIGXCPU" => Signal::SIGXCPU,
+ "SIGXFSZ" => Signal::SIGXFSZ,
+ "SIGVTALRM" => Signal::SIGVTALRM,
+ "SIGPROF" => Signal::SIGPROF,
+ "SIGWINCH" => Signal::SIGWINCH,
+ "SIGIO" => Signal::SIGIO,
+ #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
+ "SIGPWR" => Signal::SIGPWR,
+ "SIGSYS" => Signal::SIGSYS,
+ #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
+ "SIGEMT" => Signal::SIGEMT,
+ #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
+ "SIGINFO" => Signal::SIGINFO,
+ _ => return Err(Error::invalid_argument()),
+ })
+ }
+}
+
+impl AsRef<str> for Signal {
+ fn as_ref(&self) -> &str {
+ match *self {
+ Signal::SIGHUP => "SIGHUP",
+ Signal::SIGINT => "SIGINT",
+ Signal::SIGQUIT => "SIGQUIT",
+ Signal::SIGILL => "SIGILL",
+ Signal::SIGTRAP => "SIGTRAP",
+ Signal::SIGABRT => "SIGABRT",
+ Signal::SIGBUS => "SIGBUS",
+ Signal::SIGFPE => "SIGFPE",
+ Signal::SIGKILL => "SIGKILL",
+ Signal::SIGUSR1 => "SIGUSR1",
+ Signal::SIGSEGV => "SIGSEGV",
+ Signal::SIGUSR2 => "SIGUSR2",
+ Signal::SIGPIPE => "SIGPIPE",
+ Signal::SIGALRM => "SIGALRM",
+ Signal::SIGTERM => "SIGTERM",
+ #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
+ not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
+ Signal::SIGSTKFLT => "SIGSTKFLT",
+ Signal::SIGCHLD => "SIGCHLD",
+ Signal::SIGCONT => "SIGCONT",
+ Signal::SIGSTOP => "SIGSTOP",
+ Signal::SIGTSTP => "SIGTSTP",
+ Signal::SIGTTIN => "SIGTTIN",
+ Signal::SIGTTOU => "SIGTTOU",
+ Signal::SIGURG => "SIGURG",
+ Signal::SIGXCPU => "SIGXCPU",
+ Signal::SIGXFSZ => "SIGXFSZ",
+ Signal::SIGVTALRM => "SIGVTALRM",
+ Signal::SIGPROF => "SIGPROF",
+ Signal::SIGWINCH => "SIGWINCH",
+ Signal::SIGIO => "SIGIO",
+ #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
+ Signal::SIGPWR => "SIGPWR",
+ Signal::SIGSYS => "SIGSYS",
+ #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
+ Signal::SIGEMT => "SIGEMT",
+ #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
+ Signal::SIGINFO => "SIGINFO",
+ }
+ }
+}
+
+impl fmt::Display for Signal {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str(self.as_ref())
+ }
+}
+
+pub use self::Signal::*;
+
+#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
+const SIGNALS: [Signal; 31] = [
+ SIGHUP,
+ SIGINT,
+ SIGQUIT,
+ SIGILL,
+ SIGTRAP,
+ SIGABRT,
+ SIGBUS,
+ SIGFPE,
+ SIGKILL,
+ SIGUSR1,
+ SIGSEGV,
+ SIGUSR2,
+ SIGPIPE,
+ SIGALRM,
+ SIGTERM,
+ SIGSTKFLT,
+ SIGCHLD,
+ SIGCONT,
+ SIGSTOP,
+ SIGTSTP,
+ SIGTTIN,
+ SIGTTOU,
+ SIGURG,
+ SIGXCPU,
+ SIGXFSZ,
+ SIGVTALRM,
+ SIGPROF,
+ SIGWINCH,
+ SIGIO,
+ SIGPWR,
+ SIGSYS];
+#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64")))]
+const SIGNALS: [Signal; 30] = [
+ SIGHUP,
+ SIGINT,
+ SIGQUIT,
+ SIGILL,
+ SIGTRAP,
+ SIGABRT,
+ SIGBUS,
+ SIGFPE,
+ SIGKILL,
+ SIGUSR1,
+ SIGSEGV,
+ SIGUSR2,
+ SIGPIPE,
+ SIGALRM,
+ SIGTERM,
+ SIGCHLD,
+ SIGCONT,
+ SIGSTOP,
+ SIGTSTP,
+ SIGTTIN,
+ SIGTTOU,
+ SIGURG,
+ SIGXCPU,
+ SIGXFSZ,
+ SIGVTALRM,
+ SIGPROF,
+ SIGWINCH,
+ SIGIO,
+ SIGPWR,
+ SIGSYS];
+#[cfg(not(any(target_os = "linux", target_os = "android", target_os = "emscripten")))]
+const SIGNALS: [Signal; 31] = [
+ SIGHUP,
+ SIGINT,
+ SIGQUIT,
+ SIGILL,
+ SIGTRAP,
+ SIGABRT,
+ SIGBUS,
+ SIGFPE,
+ SIGKILL,
+ SIGUSR1,
+ SIGSEGV,
+ SIGUSR2,
+ SIGPIPE,
+ SIGALRM,
+ SIGTERM,
+ SIGCHLD,
+ SIGCONT,
+ SIGSTOP,
+ SIGTSTP,
+ SIGTTIN,
+ SIGTTOU,
+ SIGURG,
+ SIGXCPU,
+ SIGXFSZ,
+ SIGVTALRM,
+ SIGPROF,
+ SIGWINCH,
+ SIGIO,
+ SIGSYS,
+ SIGEMT,
+ SIGINFO];
+
+pub const NSIG: libc::c_int = 32;
+
+#[derive(Clone, Copy)]
+#[allow(missing_debug_implementations)]
+pub struct SignalIterator {
+ next: usize,
+}
+
+impl Iterator for SignalIterator {
+ type Item = Signal;
+
+ fn next(&mut self) -> Option<Signal> {
+ if self.next < SIGNALS.len() {
+ let next_signal = SIGNALS[self.next];
+ self.next += 1;
+ Some(next_signal)
+ } else {
+ None
+ }
+ }
+}
+
+impl Signal {
+ pub fn iterator() -> SignalIterator {
+ SignalIterator{next: 0}
+ }
+
+ // We do not implement the From trait, because it is supposed to be infallible.
+ // With Rust RFC 1542 comes the appropriate trait TryFrom. Once it is
+ // implemented, we'll replace this function.
+ #[inline]
+ pub fn from_c_int(signum: libc::c_int) -> Result<Signal> {
+ if 0 < signum && signum < NSIG {
+ Ok(unsafe { mem::transmute(signum) })
+ } else {
+ Err(Error::invalid_argument())
+ }
+ }
+}
+
+pub const SIGIOT : Signal = SIGABRT;
+pub const SIGPOLL : Signal = SIGIO;
+pub const SIGUNUSED : Signal = SIGSYS;
+
+libc_bitflags!{
+ pub struct SaFlags: libc::c_int {
+ SA_NOCLDSTOP;
+ SA_NOCLDWAIT;
+ SA_NODEFER;
+ SA_ONSTACK;
+ SA_RESETHAND;
+ SA_RESTART;
+ SA_SIGINFO;
+ }
+}
+
+libc_enum! {
+ #[repr(i32)]
+ pub enum SigmaskHow {
+ SIG_BLOCK,
+ SIG_UNBLOCK,
+ SIG_SETMASK,
+ }
+}
+
+#[derive(Clone, Copy)]
+#[allow(missing_debug_implementations)]
+pub struct SigSet {
+ sigset: libc::sigset_t
+}
+
+
+impl SigSet {
+ pub fn all() -> SigSet {
+ let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
+ let _ = unsafe { libc::sigfillset(&mut sigset as *mut libc::sigset_t) };
+
+ SigSet { sigset: sigset }
+ }
+
+ pub fn empty() -> SigSet {
+ let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
+ let _ = unsafe { libc::sigemptyset(&mut sigset as *mut libc::sigset_t) };
+
+ SigSet { sigset: sigset }
+ }
+
+ pub fn add(&mut self, signal: Signal) {
+ unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
+ }
+
+ pub fn clear(&mut self) {
+ unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };
+ }
+
+ pub fn remove(&mut self, signal: Signal) {
+ unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
+ }
+
+ pub fn contains(&self, signal: Signal) -> bool {
+ let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) };
+
+ match res {
+ 1 => true,
+ 0 => false,
+ _ => unreachable!("unexpected value from sigismember"),
+ }
+ }
+
+ pub fn extend(&mut self, other: &SigSet) {
+ for signal in Signal::iterator() {
+ if other.contains(signal) {
+ self.add(signal);
+ }
+ }
+ }
+
+ /// Gets the currently blocked (masked) set of signals for the calling thread.
+ pub fn thread_get_mask() -> Result<SigSet> {
+ let mut oldmask: SigSet = unsafe { mem::uninitialized() };
+ pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(&mut oldmask))?;
+ Ok(oldmask)
+ }
+
+ /// Sets the set of signals as the signal mask for the calling thread.
+ pub fn thread_set_mask(&self) -> Result<()> {
+ pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(self), None)
+ }
+
+ /// Adds the set of signals to the signal mask for the calling thread.
+ pub fn thread_block(&self) -> Result<()> {
+ pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(self), None)
+ }
+
+ /// Removes the set of signals from the signal mask for the calling thread.
+ pub fn thread_unblock(&self) -> Result<()> {
+ pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(self), None)
+ }
+
+ /// Sets the set of signals as the signal mask, and returns the old mask.
+ pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> {
+ let mut oldmask: SigSet = unsafe { mem::uninitialized() };
+ pthread_sigmask(how, Some(self), Some(&mut oldmask))?;
+ Ok(oldmask)
+ }
+
+ /// Suspends execution of the calling thread until one of the signals in the
+ /// signal mask becomes pending, and returns the accepted signal.
+ pub fn wait(&self) -> Result<Signal> {
+ let mut signum: libc::c_int = unsafe { mem::uninitialized() };
+ let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, &mut signum) };
+
+ Errno::result(res).map(|_| Signal::from_c_int(signum).unwrap())
+ }
+}
+
+impl AsRef<libc::sigset_t> for SigSet {
+ fn as_ref(&self) -> &libc::sigset_t {
+ &self.sigset
+ }
+}
+
+/// A signal handler.
+#[allow(unknown_lints)]
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum SigHandler {
+ /// Default signal handling.
+ SigDfl,
+ /// Request that the signal be ignored.
+ SigIgn,
+ /// Use the given signal-catching function, which takes in the signal.
+ Handler(extern fn(libc::c_int)),
+ /// Use the given signal-catching function, which takes in the signal, information about how
+ /// the signal was generated, and a pointer to the threads `ucontext_t`.
+ SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
+}
+
+/// Action to take on receipt of a signal. Corresponds to `sigaction`.
+#[derive(Clone, Copy)]
+#[allow(missing_debug_implementations)]
+pub struct SigAction {
+ sigaction: libc::sigaction
+}
+
+impl SigAction {
+ /// Creates a new action.
+ ///
+ /// The `SA_SIGINFO` bit in the `flags` argument is ignored (it will be set only if `handler`
+ /// is the `SigAction` variant). `mask` specifies other signals to block during execution of
+ /// the signal-catching function.
+ pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
+ let mut s = unsafe { mem::uninitialized::<libc::sigaction>() };
+ s.sa_sigaction = match handler {
+ SigHandler::SigDfl => libc::SIG_DFL,
+ SigHandler::SigIgn => libc::SIG_IGN,
+ SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
+ SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
+ };
+ s.sa_flags = match handler {
+ SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(),
+ _ => (flags - SaFlags::SA_SIGINFO).bits(),
+ };
+ s.sa_mask = mask.sigset;
+
+ SigAction { sigaction: s }
+ }
+
+ /// Returns the flags set on the action.
+ pub fn flags(&self) -> SaFlags {
+ SaFlags::from_bits_truncate(self.sigaction.sa_flags)
+ }
+
+ /// Returns the set of signals that are blocked during execution of the action's
+ /// signal-catching function.
+ pub fn mask(&self) -> SigSet {
+ SigSet { sigset: self.sigaction.sa_mask }
+ }
+
+ /// Returns the action's handler.
+ pub fn handler(&self) -> SigHandler {
+ match self.sigaction.sa_sigaction {
+ libc::SIG_DFL => SigHandler::SigDfl,
+ libc::SIG_IGN => SigHandler::SigIgn,
+ f if self.flags().contains(SaFlags::SA_SIGINFO) =>
+ SigHandler::SigAction( unsafe { mem::transmute(f) } ),
+ f => SigHandler::Handler( unsafe { mem::transmute(f) } ),
+ }
+ }
+}
+
+/// Changes the action taken by a process on receipt of a specific signal.
+///
+/// `signal` can be any signal except `SIGKILL` or `SIGSTOP`. On success, it returns the previous
+/// action for the given signal. If `sigaction` fails, no new signal handler is installed.
+///
+/// # Safety
+///
+/// Signal handlers may be called at any point during execution, which limits what is safe to do in
+/// the body of the signal-catching function. Be certain to only make syscalls that are explicitly
+/// marked safe for signal handlers and only share global data using atomics.
+pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> {
+ let mut oldact = mem::uninitialized::<libc::sigaction>();
+
+ let res =
+ libc::sigaction(signal as libc::c_int, &sigaction.sigaction as *const libc::sigaction, &mut oldact as *mut libc::sigaction);
+
+ Errno::result(res).map(|_| SigAction { sigaction: oldact })
+}
+
+/// Signal management (see [signal(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html))
+///
+/// Installs `handler` for the given `signal`, returning the previous signal
+/// handler. `signal` should only be used following another call to `signal` or
+/// if the current handler is the default. The return value of `signal` is
+/// undefined after setting the handler with [`sigaction`][SigActionFn].
+///
+/// # Safety
+///
+/// If the pointer to the previous signal handler is invalid, undefined
+/// behavior could be invoked when casting it back to a [`SigAction`][SigActionStruct].
+///
+/// # Examples
+///
+/// Ignore `SIGINT`:
+///
+/// ```no_run
+/// # use nix::sys::signal::{self, Signal, SigHandler};
+/// unsafe { signal::signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap();
+/// ```
+///
+/// Use a signal handler to set a flag variable:
+///
+/// ```no_run
+/// # #[macro_use] extern crate lazy_static;
+/// # extern crate libc;
+/// # extern crate nix;
+/// # use std::sync::atomic::{AtomicBool, Ordering};
+/// # use nix::sys::signal::{self, Signal, SigHandler};
+/// lazy_static! {
+/// static ref SIGNALED: AtomicBool = AtomicBool::new(false);
+/// }
+///
+/// extern fn handle_sigint(signal: libc::c_int) {
+/// let signal = Signal::from_c_int(signal).unwrap();
+/// SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed);
+/// }
+///
+/// fn main() {
+/// let handler = SigHandler::Handler(handle_sigint);
+/// unsafe { signal::signal(Signal::SIGINT, handler) }.unwrap();
+/// }
+/// ```
+///
+/// # Errors
+///
+/// Returns [`Error::UnsupportedOperation`] if `handler` is
+/// [`SigAction`][SigActionStruct]. Use [`sigaction`][SigActionFn] instead.
+///
+/// `signal` also returns any error from `libc::signal`, such as when an attempt
+/// is made to catch a signal that cannot be caught or to ignore a signal that
+/// cannot be ignored.
+///
+/// [`Error::UnsupportedOperation`]: ../../enum.Error.html#variant.UnsupportedOperation
+/// [SigActionStruct]: struct.SigAction.html
+/// [sigactionFn]: fn.sigaction.html
+pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> {
+ let signal = signal as libc::c_int;
+ let res = match handler {
+ SigHandler::SigDfl => libc::signal(signal, libc::SIG_DFL),
+ SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN),
+ SigHandler::Handler(handler) => libc::signal(signal, handler as libc::sighandler_t),
+ SigHandler::SigAction(_) => return Err(Error::UnsupportedOperation),
+ };
+ Errno::result(res).map(|oldhandler| {
+ match oldhandler {
+ libc::SIG_DFL => SigHandler::SigDfl,
+ libc::SIG_IGN => SigHandler::SigIgn,
+ f => SigHandler::Handler(mem::transmute(f)),
+ }
+ })
+}
+
+/// Manages the signal mask (set of blocked signals) for the calling thread.
+///
+/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
+/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored,
+/// and no modification will take place.
+///
+/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it.
+///
+/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset,
+/// and then it will be updated with `set`.
+///
+/// If both `set` and `oldset` is None, this function is a no-op.
+///
+/// For more information, visit the [`pthread_sigmask`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html),
+/// or [`sigprocmask`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html) man pages.
+pub fn pthread_sigmask(how: SigmaskHow,
+ set: Option<&SigSet>,
+ oldset: Option<&mut SigSet>) -> Result<()> {
+ if set.is_none() && oldset.is_none() {
+ return Ok(())
+ }
+
+ let res = unsafe {
+ // if set or oldset is None, pass in null pointers instead
+ libc::pthread_sigmask(how as libc::c_int,
+ set.map_or_else(ptr::null::<libc::sigset_t>,
+ |s| &s.sigset as *const libc::sigset_t),
+ oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
+ |os| &mut os.sigset as *mut libc::sigset_t))
+ };
+
+ Errno::result(res).map(drop)
+}
+
+/// Examine and change blocked signals.
+///
+/// For more informations see the [`sigprocmask` man
+/// pages](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html).
+pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> {
+ if set.is_none() && oldset.is_none() {
+ return Ok(())
+ }
+
+ let res = unsafe {
+ // if set or oldset is None, pass in null pointers instead
+ libc::sigprocmask(how as libc::c_int,
+ set.map_or_else(ptr::null::<libc::sigset_t>,
+ |s| &s.sigset as *const libc::sigset_t),
+ oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
+ |os| &mut os.sigset as *mut libc::sigset_t))
+ };
+
+ Errno::result(res).map(drop)
+}
+
+pub fn kill<T: Into<Option<Signal>>>(pid: ::unistd::Pid, signal: T) -> Result<()> {
+ let res = unsafe { libc::kill(pid.into(),
+ match signal.into() {
+ Some(s) => s as libc::c_int,
+ None => 0,
+ }) };
+
+ Errno::result(res).map(drop)
+}
+
+pub fn raise(signal: Signal) -> Result<()> {
+ let res = unsafe { libc::raise(signal as libc::c_int) };
+
+ Errno::result(res).map(drop)
+}
+
+
+#[cfg(target_os = "freebsd")]
+pub type type_of_thread_id = libc::lwpid_t;
+#[cfg(target_os = "linux")]
+pub type type_of_thread_id = libc::pid_t;
+
+/// Used to request asynchronous notification of certain events, for example,
+/// with POSIX AIO, POSIX message queues, and POSIX timers.
+// sigval is actually a union of a int and a void*. But it's never really used
+// as a pointer, because neither libc nor the kernel ever dereference it. nix
+// therefore presents it as an intptr_t, which is how kevent uses it.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum SigevNotify {
+ /// No notification will be delivered
+ SigevNone,
+ /// The signal given by `signal` will be delivered to the process. The
+ /// value in `si_value` will be present in the `si_value` field of the
+ /// `siginfo_t` structure of the queued signal.
+ SigevSignal { signal: Signal, si_value: libc::intptr_t },
+ // Note: SIGEV_THREAD is not implemented because libc::sigevent does not
+ // expose a way to set the union members needed by SIGEV_THREAD.
+ /// A new `kevent` is posted to the kqueue `kq`. The `kevent`'s `udata`
+ /// field will contain the value in `udata`.
+ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
+ SigevKevent { kq: RawFd, udata: libc::intptr_t },
+ /// The signal `signal` is queued to the thread whose LWP ID is given in
+ /// `thread_id`. The value stored in `si_value` will be present in the
+ /// `si_value` of the `siginfo_t` structure of the queued signal.
+ #[cfg(any(target_os = "freebsd", target_os = "linux"))]
+ SigevThreadId { signal: Signal, thread_id: type_of_thread_id,
+ si_value: libc::intptr_t },
+}
+
+#[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)]
+ #[derive(Clone, Copy)]
+ 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}
+ }
+
+ #[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(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
+ }
+ }
+
+ 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()
+ }
+
+ #[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 }
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use std::thread;
+ use super::*;
+
+ #[test]
+ fn test_contains() {
+ let mut mask = SigSet::empty();
+ mask.add(SIGUSR1);
+
+ assert!(mask.contains(SIGUSR1));
+ assert!(!mask.contains(SIGUSR2));
+
+ let all = SigSet::all();
+ assert!(all.contains(SIGUSR1));
+ assert!(all.contains(SIGUSR2));
+ }
+
+ #[test]
+ fn test_clear() {
+ let mut set = SigSet::all();
+ set.clear();
+ for signal in Signal::iterator() {
+ assert!(!set.contains(signal));
+ }
+ }
+
+ #[test]
+ fn test_from_str_round_trips() {
+ for signal in Signal::iterator() {
+ assert_eq!(signal.as_ref().parse::<Signal>().unwrap(), signal);
+ assert_eq!(signal.to_string().parse::<Signal>().unwrap(), signal);
+ }
+ }
+
+ #[test]
+ fn test_from_str_invalid_value() {
+ let errval = Err(Error::Sys(Errno::EINVAL));
+ assert_eq!("NOSIGNAL".parse::<Signal>(), errval);
+ assert_eq!("kill".parse::<Signal>(), errval);
+ assert_eq!("9".parse::<Signal>(), errval);
+ }
+
+ #[test]
+ fn test_extend() {
+ let mut one_signal = SigSet::empty();
+ one_signal.add(SIGUSR1);
+
+ let mut two_signals = SigSet::empty();
+ two_signals.add(SIGUSR2);
+ two_signals.extend(&one_signal);
+
+ assert!(two_signals.contains(SIGUSR1));
+ assert!(two_signals.contains(SIGUSR2));
+ }
+
+ // This test doesn't actually test get_mask functionality, see the set_mask test for that.
+ #[test]
+ fn test_thread_signal_get_mask() {
+ assert!(SigSet::thread_get_mask().is_ok());
+ }
+
+ #[test]
+ fn test_thread_signal_set_mask() {
+ thread::spawn(|| {
+ let prev_mask = SigSet::thread_get_mask()
+ .expect("Failed to get existing signal mask!");
+
+ let mut test_mask = prev_mask;
+ test_mask.add(SIGUSR1);
+
+ assert!(test_mask.thread_set_mask().is_ok());
+ let new_mask = SigSet::thread_get_mask()
+ .expect("Failed to get new mask!");
+
+ assert!(new_mask.contains(SIGUSR1));
+ assert!(!new_mask.contains(SIGUSR2));
+
+ prev_mask.thread_set_mask().expect("Failed to revert signal mask!");
+ }).join().unwrap();
+ }
+
+ #[test]
+ fn test_thread_signal_block() {
+ thread::spawn(|| {
+ let mut mask = SigSet::empty();
+ mask.add(SIGUSR1);
+
+ assert!(mask.thread_block().is_ok());
+
+ assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
+ }).join().unwrap();
+ }
+
+ #[test]
+ fn test_thread_signal_unblock() {
+ thread::spawn(|| {
+ let mut mask = SigSet::empty();
+ mask.add(SIGUSR1);
+
+ assert!(mask.thread_unblock().is_ok());
+
+ assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
+ }).join().unwrap();
+ }
+
+ #[test]
+ fn test_thread_signal_swap() {
+ thread::spawn(|| {
+ let mut mask = SigSet::empty();
+ mask.add(SIGUSR1);
+ mask.thread_block().unwrap();
+
+ assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
+
+ let mut mask2 = SigSet::empty();
+ mask2.add(SIGUSR2);
+
+ let oldmask = mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK)
+ .unwrap();
+
+ assert!(oldmask.contains(SIGUSR1));
+ assert!(!oldmask.contains(SIGUSR2));
+
+ assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2));
+ }).join().unwrap();
+ }
+
+ #[test]
+ fn test_sigaction() {
+ use libc;
+ thread::spawn(|| {
+ extern fn test_sigaction_handler(_: libc::c_int) {}
+ extern fn test_sigaction_action(_: libc::c_int,
+ _: *mut libc::siginfo_t, _: *mut libc::c_void) {}
+
+ let handler_sig = SigHandler::Handler(test_sigaction_handler);
+
+ let flags = SaFlags::SA_ONSTACK | SaFlags::SA_RESTART |
+ SaFlags::SA_SIGINFO;
+
+ let mut mask = SigSet::empty();
+ mask.add(SIGUSR1);
+
+ let action_sig = SigAction::new(handler_sig, flags, mask);
+
+ assert_eq!(action_sig.flags(),
+ SaFlags::SA_ONSTACK | SaFlags::SA_RESTART);
+ assert_eq!(action_sig.handler(), handler_sig);
+
+ mask = action_sig.mask();
+ assert!(mask.contains(SIGUSR1));
+ assert!(!mask.contains(SIGUSR2));
+
+ let handler_act = SigHandler::SigAction(test_sigaction_action);
+ let action_act = SigAction::new(handler_act, flags, mask);
+ assert_eq!(action_act.handler(), handler_act);
+
+ let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask);
+ assert_eq!(action_dfl.handler(), SigHandler::SigDfl);
+
+ let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask);
+ assert_eq!(action_ign.handler(), SigHandler::SigIgn);
+ }).join().unwrap();
+ }
+
+ // TODO(#251): Re-enable after figuring out flakiness.
+ #[cfg(not(any(target_os = "macos", target_os = "ios")))]
+ #[test]
+ fn test_sigwait() {
+ thread::spawn(|| {
+ let mut mask = SigSet::empty();
+ mask.add(SIGUSR1);
+ mask.add(SIGUSR2);
+ mask.thread_block().unwrap();
+
+ raise(SIGUSR1).unwrap();
+ assert_eq!(mask.wait().unwrap(), SIGUSR1);
+ }).join().unwrap();
+ }
+}
diff --git a/third_party/rust/nix/src/sys/signalfd.rs b/third_party/rust/nix/src/sys/signalfd.rs
new file mode 100644
index 0000000000..5425a27be9
--- /dev/null
+++ b/third_party/rust/nix/src/sys/signalfd.rs
@@ -0,0 +1,170 @@
+//! Interface for the `signalfd` syscall.
+//!
+//! # Signal discarding
+//! When a signal can't be delivered to a process (or thread), it will become a pending signal.
+//! Failure to deliver could happen if the signal is blocked by every thread in the process or if
+//! the signal handler is still handling a previous signal.
+//!
+//! If a signal is sent to a process (or thread) that already has a pending signal of the same
+//! type, it will be discarded. This means that if signals of the same type are received faster than
+//! they are processed, some of those signals will be dropped. Because of this limitation,
+//! `signalfd` in itself cannot be used for reliable communication between processes or threads.
+//!
+//! Once the signal is unblocked, or the signal handler is finished, and a signal is still pending
+//! (ie. not consumed from a signalfd) it will be delivered to the signal handler.
+//!
+//! Please note that signal discarding is not specific to `signalfd`, but also happens with regular
+//! signal handlers.
+use libc;
+use unistd;
+use {Error, Result};
+use errno::Errno;
+pub use sys::signal::{self, SigSet};
+pub use libc::signalfd_siginfo as siginfo;
+
+use std::os::unix::io::{RawFd, AsRawFd};
+use std::mem;
+
+
+libc_bitflags!{
+ pub struct SfdFlags: libc::c_int {
+ SFD_NONBLOCK;
+ SFD_CLOEXEC;
+ }
+}
+
+pub const SIGNALFD_NEW: RawFd = -1;
+pub const SIGNALFD_SIGINFO_SIZE: usize = 128;
+
+/// Creates a new file descriptor for reading signals.
+///
+/// **Important:** please read the module level documentation about signal discarding before using
+/// this function!
+///
+/// The `mask` parameter specifies the set of signals that can be accepted via this file descriptor.
+///
+/// A signal must be blocked on every thread in a process, otherwise it won't be visible from
+/// signalfd (the default handler will be invoked instead).
+///
+/// See [the signalfd man page for more information](http://man7.org/linux/man-pages/man2/signalfd.2.html)
+pub fn signalfd(fd: RawFd, mask: &SigSet, flags: SfdFlags) -> Result<RawFd> {
+ unsafe {
+ Errno::result(libc::signalfd(fd as libc::c_int, mask.as_ref(), flags.bits()))
+ }
+}
+
+/// A helper struct for creating, reading and closing a `signalfd` instance.
+///
+/// **Important:** please read the module level documentation about signal discarding before using
+/// this struct!
+///
+/// # Examples
+///
+/// ```
+/// # use nix::sys::signalfd::*;
+/// // Set the thread to block the SIGUSR1 signal, otherwise the default handler will be used
+/// let mut mask = SigSet::empty();
+/// mask.add(signal::SIGUSR1);
+/// mask.thread_block().unwrap();
+///
+/// // Signals are queued up on the file descriptor
+/// let mut sfd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap();
+///
+/// match sfd.read_signal() {
+/// // we caught a signal
+/// Ok(Some(sig)) => (),
+/// // there were no signals waiting (only happens when the SFD_NONBLOCK flag is set,
+/// // otherwise the read_signal call blocks)
+/// Ok(None) => (),
+/// Err(err) => (), // some error happend
+/// }
+/// ```
+#[derive(Clone, Debug, Eq, Hash, PartialEq)]
+pub struct SignalFd(RawFd);
+
+impl SignalFd {
+ pub fn new(mask: &SigSet) -> Result<SignalFd> {
+ Self::with_flags(mask, SfdFlags::empty())
+ }
+
+ pub fn with_flags(mask: &SigSet, flags: SfdFlags) -> Result<SignalFd> {
+ let fd = signalfd(SIGNALFD_NEW, mask, flags)?;
+
+ Ok(SignalFd(fd))
+ }
+
+ pub fn set_mask(&mut self, mask: &SigSet) -> Result<()> {
+ signalfd(self.0, mask, SfdFlags::empty()).map(drop)
+ }
+
+ pub fn read_signal(&mut self) -> Result<Option<siginfo>> {
+ let mut buffer: [u8; SIGNALFD_SIGINFO_SIZE] = unsafe { mem::uninitialized() };
+
+ match unistd::read(self.0, &mut buffer) {
+ Ok(SIGNALFD_SIGINFO_SIZE) => Ok(Some(unsafe { mem::transmute(buffer) })),
+ Ok(_) => unreachable!("partial read on signalfd"),
+ Err(Error::Sys(Errno::EAGAIN)) => Ok(None),
+ Err(error) => Err(error)
+ }
+ }
+}
+
+impl Drop for SignalFd {
+ fn drop(&mut self) {
+ let _ = unistd::close(self.0);
+ }
+}
+
+impl AsRawFd for SignalFd {
+ fn as_raw_fd(&self) -> RawFd {
+ self.0
+ }
+}
+
+impl Iterator for SignalFd {
+ type Item = siginfo;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ match self.read_signal() {
+ Ok(Some(sig)) => Some(sig),
+ Ok(None) | Err(_) => None,
+ }
+ }
+}
+
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use std::mem;
+ use libc;
+
+
+ #[test]
+ fn check_siginfo_size() {
+ assert_eq!(mem::size_of::<libc::signalfd_siginfo>(), SIGNALFD_SIGINFO_SIZE);
+ }
+
+ #[test]
+ fn create_signalfd() {
+ let mask = SigSet::empty();
+ let fd = SignalFd::new(&mask);
+ assert!(fd.is_ok());
+ }
+
+ #[test]
+ fn create_signalfd_with_opts() {
+ let mask = SigSet::empty();
+ let fd = SignalFd::with_flags(&mask, SfdFlags::SFD_CLOEXEC | SfdFlags::SFD_NONBLOCK);
+ assert!(fd.is_ok());
+ }
+
+ #[test]
+ fn read_empty_signalfd() {
+ let mask = SigSet::empty();
+ let mut fd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap();
+
+ let res = fd.read_signal();
+ assert!(res.unwrap().is_none());
+ }
+}
diff --git a/third_party/rust/nix/src/sys/socket/addr.rs b/third_party/rust/nix/src/sys/socket/addr.rs
new file mode 100644
index 0000000000..9ec668985b
--- /dev/null
+++ b/third_party/rust/nix/src/sys/socket/addr.rs
@@ -0,0 +1,1408 @@
+use super::sa_family_t;
+use {Error, Result, NixPath};
+use errno::Errno;
+use libc;
+use std::{fmt, hash, mem, net, ptr, slice};
+use std::ffi::OsStr;
+use std::path::Path;
+use std::os::unix::ffi::OsStrExt;
+#[cfg(any(target_os = "android", target_os = "linux"))]
+use ::sys::socket::addr::netlink::NetlinkAddr;
+#[cfg(any(target_os = "ios", target_os = "macos"))]
+use std::os::unix::io::RawFd;
+#[cfg(any(target_os = "ios", target_os = "macos"))]
+use ::sys::socket::addr::sys_control::SysControlAddr;
+#[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+pub use self::datalink::LinkAddr;
+
+/// These constants specify the protocol family to be used
+/// in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html)
+#[repr(i32)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
+pub enum AddressFamily {
+ /// Local communication (see [`unix(7)`](http://man7.org/linux/man-pages/man7/unix.7.html))
+ Unix = libc::AF_UNIX,
+ /// IPv4 Internet protocols (see [`ip(7)`](http://man7.org/linux/man-pages/man7/ip.7.html))
+ Inet = libc::AF_INET,
+ /// IPv6 Internet protocols (see [`ipv6(7)`](http://man7.org/linux/man-pages/man7/ipv6.7.html))
+ Inet6 = libc::AF_INET6,
+ /// Kernel user interface device (see [`netlink(7)`](http://man7.org/linux/man-pages/man7/netlink.7.html))
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Netlink = libc::AF_NETLINK,
+ /// Low level packet interface (see [`packet(7)`](http://man7.org/linux/man-pages/man7/packet.7.html))
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Packet = libc::AF_PACKET,
+ /// KEXT Controls and Notifications
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ System = libc::AF_SYSTEM,
+ /// Amateur radio AX.25 protocol
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Ax25 = libc::AF_AX25,
+ /// IPX - Novell protocols
+ Ipx = libc::AF_IPX,
+ /// AppleTalk
+ AppleTalk = libc::AF_APPLETALK,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ NetRom = libc::AF_NETROM,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Bridge = libc::AF_BRIDGE,
+ /// Access to raw ATM PVCs
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ AtmPvc = libc::AF_ATMPVC,
+ /// ITU-T X.25 / ISO-8208 protocol (see [`x25(7)`](http://man7.org/linux/man-pages/man7/x25.7.html))
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ X25 = libc::AF_X25,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Rose = libc::AF_ROSE,
+ Decnet = libc::AF_DECnet,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ NetBeui = libc::AF_NETBEUI,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Security = libc::AF_SECURITY,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Key = libc::AF_KEY,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Ash = libc::AF_ASH,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Econet = libc::AF_ECONET,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ AtmSvc = libc::AF_ATMSVC,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Rds = libc::AF_RDS,
+ Sna = libc::AF_SNA,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Irda = libc::AF_IRDA,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Pppox = libc::AF_PPPOX,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Wanpipe = libc::AF_WANPIPE,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Llc = libc::AF_LLC,
+ #[cfg(target_os = "linux")]
+ Ib = libc::AF_IB,
+ #[cfg(target_os = "linux")]
+ Mpls = libc::AF_MPLS,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Can = libc::AF_CAN,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Tipc = libc::AF_TIPC,
+ #[cfg(not(any(target_os = "ios", target_os = "macos")))]
+ Bluetooth = libc::AF_BLUETOOTH,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Iucv = libc::AF_IUCV,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ RxRpc = libc::AF_RXRPC,
+ Isdn = libc::AF_ISDN,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Phonet = libc::AF_PHONET,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Ieee802154 = libc::AF_IEEE802154,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Caif = libc::AF_CAIF,
+ /// Interface to kernel crypto API
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Alg = libc::AF_ALG,
+ #[cfg(target_os = "linux")]
+ Nfc = libc::AF_NFC,
+ #[cfg(target_os = "linux")]
+ Vsock = libc::AF_VSOCK,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ ImpLink = libc::AF_IMPLINK,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Pup = libc::AF_PUP,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Chaos = libc::AF_CHAOS,
+ #[cfg(any(target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Ns = libc::AF_NS,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Iso = libc::AF_ISO,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Datakit = libc::AF_DATAKIT,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Ccitt = libc::AF_CCITT,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Dli = libc::AF_DLI,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Lat = libc::AF_LAT,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Hylink = libc::AF_HYLINK,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Link = libc::AF_LINK,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Coip = libc::AF_COIP,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Cnt = libc::AF_CNT,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Natm = libc::AF_NATM,
+ /// Unspecified address family, (see [`getaddrinfo(3)`](http://man7.org/linux/man-pages/man3/getaddrinfo.3.html))
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Unspec = libc::AF_UNSPEC,
+}
+
+impl AddressFamily {
+ /// Create a new `AddressFamily` from an integer value retrieved from `libc`, usually from
+ /// the `sa_family` field of a `sockaddr`.
+ ///
+ /// Currently only supports these address families: Unix, Inet (v4 & v6), Netlink, Link/Packet
+ /// and System. Returns None for unsupported or unknown address families.
+ pub fn from_i32(family: i32) -> Option<AddressFamily> {
+ match family {
+ libc::AF_UNIX => Some(AddressFamily::Unix),
+ libc::AF_INET => Some(AddressFamily::Inet),
+ libc::AF_INET6 => Some(AddressFamily::Inet6),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ libc::AF_NETLINK => Some(AddressFamily::Netlink),
+ #[cfg(any(target_os = "macos", target_os = "macos"))]
+ libc::AF_SYSTEM => Some(AddressFamily::System),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ libc::AF_PACKET => Some(AddressFamily::Packet),
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ libc::AF_LINK => Some(AddressFamily::Link),
+ _ => None
+ }
+ }
+}
+
+#[derive(Copy)]
+pub enum InetAddr {
+ V4(libc::sockaddr_in),
+ V6(libc::sockaddr_in6),
+}
+
+impl InetAddr {
+ pub fn from_std(std: &net::SocketAddr) -> InetAddr {
+ match *std {
+ net::SocketAddr::V4(ref addr) => {
+ InetAddr::V4(libc::sockaddr_in {
+ sin_family: AddressFamily::Inet as sa_family_t,
+ sin_port: addr.port().to_be(), // network byte order
+ sin_addr: Ipv4Addr::from_std(addr.ip()).0,
+ .. unsafe { mem::zeroed() }
+ })
+ }
+ net::SocketAddr::V6(ref addr) => {
+ InetAddr::V6(libc::sockaddr_in6 {
+ sin6_family: AddressFamily::Inet6 as sa_family_t,
+ sin6_port: addr.port().to_be(), // network byte order
+ sin6_addr: Ipv6Addr::from_std(addr.ip()).0,
+ sin6_flowinfo: addr.flowinfo(), // host byte order
+ sin6_scope_id: addr.scope_id(), // host byte order
+ .. unsafe { mem::zeroed() }
+ })
+ }
+ }
+ }
+
+ pub fn new(ip: IpAddr, port: u16) -> InetAddr {
+ match ip {
+ IpAddr::V4(ref ip) => {
+ InetAddr::V4(libc::sockaddr_in {
+ sin_family: AddressFamily::Inet as sa_family_t,
+ sin_port: port.to_be(),
+ sin_addr: ip.0,
+ .. unsafe { mem::zeroed() }
+ })
+ }
+ IpAddr::V6(ref ip) => {
+ InetAddr::V6(libc::sockaddr_in6 {
+ sin6_family: AddressFamily::Inet6 as sa_family_t,
+ sin6_port: port.to_be(),
+ sin6_addr: ip.0,
+ .. unsafe { mem::zeroed() }
+ })
+ }
+ }
+ }
+ /// Gets the IP address associated with this socket address.
+ pub fn ip(&self) -> IpAddr {
+ match *self {
+ InetAddr::V4(ref sa) => IpAddr::V4(Ipv4Addr(sa.sin_addr)),
+ InetAddr::V6(ref sa) => IpAddr::V6(Ipv6Addr(sa.sin6_addr)),
+ }
+ }
+
+ /// Gets the port number associated with this socket address
+ pub fn port(&self) -> u16 {
+ match *self {
+ InetAddr::V6(ref sa) => u16::from_be(sa.sin6_port),
+ InetAddr::V4(ref sa) => u16::from_be(sa.sin_port),
+ }
+ }
+
+ pub fn to_std(&self) -> net::SocketAddr {
+ match *self {
+ InetAddr::V4(ref sa) => net::SocketAddr::V4(
+ net::SocketAddrV4::new(
+ Ipv4Addr(sa.sin_addr).to_std(),
+ self.port())),
+ InetAddr::V6(ref sa) => net::SocketAddr::V6(
+ net::SocketAddrV6::new(
+ Ipv6Addr(sa.sin6_addr).to_std(),
+ self.port(),
+ sa.sin6_flowinfo,
+ sa.sin6_scope_id)),
+ }
+ }
+
+ pub fn to_str(&self) -> String {
+ format!("{}", self)
+ }
+}
+
+impl PartialEq for InetAddr {
+ fn eq(&self, other: &InetAddr) -> bool {
+ match (*self, *other) {
+ (InetAddr::V4(ref a), InetAddr::V4(ref b)) => {
+ a.sin_port == b.sin_port &&
+ a.sin_addr.s_addr == b.sin_addr.s_addr
+ }
+ (InetAddr::V6(ref a), InetAddr::V6(ref b)) => {
+ a.sin6_port == b.sin6_port &&
+ a.sin6_addr.s6_addr == b.sin6_addr.s6_addr &&
+ a.sin6_flowinfo == b.sin6_flowinfo &&
+ a.sin6_scope_id == b.sin6_scope_id
+ }
+ _ => false,
+ }
+ }
+}
+
+impl Eq for InetAddr {
+}
+
+impl hash::Hash for InetAddr {
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ match *self {
+ InetAddr::V4(ref a) => {
+ ( a.sin_family,
+ a.sin_port,
+ a.sin_addr.s_addr ).hash(s)
+ }
+ InetAddr::V6(ref a) => {
+ ( a.sin6_family,
+ a.sin6_port,
+ &a.sin6_addr.s6_addr,
+ a.sin6_flowinfo,
+ a.sin6_scope_id ).hash(s)
+ }
+ }
+ }
+}
+
+impl Clone for InetAddr {
+ fn clone(&self) -> InetAddr {
+ *self
+ }
+}
+
+impl fmt::Display for InetAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ InetAddr::V4(_) => write!(f, "{}:{}", self.ip(), self.port()),
+ InetAddr::V6(_) => write!(f, "[{}]:{}", self.ip(), self.port()),
+ }
+ }
+}
+
+impl fmt::Debug for InetAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+/*
+ *
+ * ===== IpAddr =====
+ *
+ */
+#[derive(Clone, Copy)]
+pub enum IpAddr {
+ V4(Ipv4Addr),
+ V6(Ipv6Addr),
+}
+
+impl IpAddr {
+ /// Create a new IpAddr that contains an IPv4 address.
+ ///
+ /// The result will represent the IP address a.b.c.d
+ pub fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr {
+ IpAddr::V4(Ipv4Addr::new(a, b, c, d))
+ }
+
+ /// Create a new IpAddr that contains an IPv6 address.
+ ///
+ /// The result will represent the IP address a:b:c:d:e:f
+ pub fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> IpAddr {
+ IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h))
+ }
+
+ /*
+ pub fn from_std(std: &net::IpAddr) -> IpAddr {
+ match *std {
+ net::IpAddr::V4(ref std) => IpAddr::V4(Ipv4Addr::from_std(std)),
+ net::IpAddr::V6(ref std) => IpAddr::V6(Ipv6Addr::from_std(std)),
+ }
+ }
+ pub fn to_std(&self) -> net::IpAddr {
+ match *self {
+ IpAddr::V4(ref ip) => net::IpAddr::V4(ip.to_std()),
+ IpAddr::V6(ref ip) => net::IpAddr::V6(ip.to_std()),
+ }
+ }
+ */
+}
+
+impl fmt::Display for IpAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ IpAddr::V4(ref v4) => v4.fmt(f),
+ IpAddr::V6(ref v6) => v6.fmt(f)
+ }
+ }
+}
+
+impl fmt::Debug for IpAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+/*
+ *
+ * ===== Ipv4Addr =====
+ *
+ */
+
+#[derive(Copy)]
+pub struct Ipv4Addr(pub libc::in_addr);
+
+impl Ipv4Addr {
+ pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
+ let ip = (((a as u32) << 24) |
+ ((b as u32) << 16) |
+ ((c as u32) << 8) |
+ ((d as u32) << 0)).to_be();
+
+ Ipv4Addr(libc::in_addr { s_addr: ip })
+ }
+
+ pub fn from_std(std: &net::Ipv4Addr) -> Ipv4Addr {
+ let bits = std.octets();
+ Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
+ }
+
+ pub fn any() -> Ipv4Addr {
+ Ipv4Addr(libc::in_addr { s_addr: libc::INADDR_ANY })
+ }
+
+ pub fn octets(&self) -> [u8; 4] {
+ let bits = u32::from_be(self.0.s_addr);
+ [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8]
+ }
+
+ pub fn to_std(&self) -> net::Ipv4Addr {
+ let bits = self.octets();
+ net::Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
+ }
+}
+
+impl PartialEq for Ipv4Addr {
+ fn eq(&self, other: &Ipv4Addr) -> bool {
+ self.0.s_addr == other.0.s_addr
+ }
+}
+
+impl Eq for Ipv4Addr {
+}
+
+impl hash::Hash for Ipv4Addr {
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ let saddr = self.0.s_addr;
+ saddr.hash(s)
+ }
+}
+
+impl Clone for Ipv4Addr {
+ fn clone(&self) -> Ipv4Addr {
+ *self
+ }
+}
+
+impl fmt::Display for Ipv4Addr {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ let octets = self.octets();
+ write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
+ }
+}
+
+impl fmt::Debug for Ipv4Addr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+/*
+ *
+ * ===== Ipv6Addr =====
+ *
+ */
+
+#[derive(Clone, Copy)]
+pub struct Ipv6Addr(pub libc::in6_addr);
+
+// Note that IPv6 addresses are stored in big endian order on all architectures.
+// See https://tools.ietf.org/html/rfc1700 or consult your favorite search
+// engine.
+
+macro_rules! to_u8_array {
+ ($($num:ident),*) => {
+ [ $(($num>>8) as u8, ($num&0xff) as u8,)* ]
+ }
+}
+
+macro_rules! to_u16_array {
+ ($slf:ident, $($first:expr, $second:expr),*) => {
+ [$( (($slf.0.s6_addr[$first] as u16) << 8) + $slf.0.s6_addr[$second] as u16,)*]
+ }
+}
+
+impl Ipv6Addr {
+ pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
+ let mut in6_addr_var: libc::in6_addr = unsafe{mem::uninitialized()};
+ in6_addr_var.s6_addr = to_u8_array!(a,b,c,d,e,f,g,h);
+ Ipv6Addr(in6_addr_var)
+ }
+
+ pub fn from_std(std: &net::Ipv6Addr) -> Ipv6Addr {
+ let s = std.segments();
+ Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7])
+ }
+
+ /// Return the eight 16-bit segments that make up this address
+ pub fn segments(&self) -> [u16; 8] {
+ to_u16_array!(self, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)
+ }
+
+ pub fn to_std(&self) -> net::Ipv6Addr {
+ let s = self.segments();
+ net::Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7])
+ }
+}
+
+impl fmt::Display for Ipv6Addr {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ self.to_std().fmt(fmt)
+ }
+}
+
+impl fmt::Debug for Ipv6Addr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+/*
+ *
+ * ===== UnixAddr =====
+ *
+ */
+
+/// A wrapper around `sockaddr_un`.
+///
+/// This also tracks the length of `sun_path` address (excluding
+/// a terminating null), because it may not be null-terminated. For example,
+/// unconnected and Linux abstract sockets are never null-terminated, and POSIX
+/// does not require that `sun_len` include the terminating null even for normal
+/// sockets. Note that the actual sockaddr length is greater by
+/// `offset_of!(libc::sockaddr_un, sun_path)`
+#[derive(Copy)]
+pub struct UnixAddr(pub libc::sockaddr_un, pub usize);
+
+impl UnixAddr {
+ /// Create a new sockaddr_un representing a filesystem path.
+ pub fn new<P: ?Sized + NixPath>(path: &P) -> Result<UnixAddr> {
+ path.with_nix_path(|cstr| {
+ unsafe {
+ let mut ret = libc::sockaddr_un {
+ sun_family: AddressFamily::Unix as sa_family_t,
+ .. mem::zeroed()
+ };
+
+ let bytes = cstr.to_bytes();
+
+ if bytes.len() > ret.sun_path.len() {
+ return Err(Error::Sys(Errno::ENAMETOOLONG));
+ }
+
+ ptr::copy_nonoverlapping(bytes.as_ptr(),
+ ret.sun_path.as_mut_ptr() as *mut u8,
+ bytes.len());
+
+ Ok(UnixAddr(ret, bytes.len()))
+ }
+ })?
+ }
+
+ /// Create a new `sockaddr_un` representing an address in the "abstract namespace".
+ ///
+ /// The leading null byte for the abstract namespace is automatically added;
+ /// thus the input `path` is expected to be the bare name, not null-prefixed.
+ /// This is a Linux-specific extension, primarily used to allow chrooted
+ /// processes to communicate with processes having a different filesystem view.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ pub fn new_abstract(path: &[u8]) -> Result<UnixAddr> {
+ unsafe {
+ let mut ret = libc::sockaddr_un {
+ sun_family: AddressFamily::Unix as sa_family_t,
+ .. mem::zeroed()
+ };
+
+ if path.len() + 1 > ret.sun_path.len() {
+ return Err(Error::Sys(Errno::ENAMETOOLONG));
+ }
+
+ // Abstract addresses are represented by sun_path[0] ==
+ // b'\0', so copy starting one byte in.
+ ptr::copy_nonoverlapping(path.as_ptr(),
+ ret.sun_path.as_mut_ptr().offset(1) as *mut u8,
+ path.len());
+
+ Ok(UnixAddr(ret, path.len() + 1))
+ }
+ }
+
+ fn sun_path(&self) -> &[u8] {
+ unsafe { slice::from_raw_parts(self.0.sun_path.as_ptr() as *const u8, self.1) }
+ }
+
+ /// If this address represents a filesystem path, return that path.
+ pub fn path(&self) -> Option<&Path> {
+ if self.1 == 0 || self.0.sun_path[0] == 0 {
+ // unnamed or abstract
+ None
+ } else {
+ let p = self.sun_path();
+ // POSIX only requires that `sun_len` be at least long enough to
+ // contain the pathname, and it need not be null-terminated. So we
+ // need to create a string that is the shorter of the
+ // null-terminated length or the full length.
+ let ptr = &self.0.sun_path as *const libc::c_char;
+ let reallen = unsafe { libc::strnlen(ptr, p.len()) };
+ Some(Path::new(<OsStr as OsStrExt>::from_bytes(&p[..reallen])))
+ }
+ }
+
+ /// If this address represents an abstract socket, return its name.
+ ///
+ /// For abstract sockets only the bare name is returned, without the
+ /// leading null byte. `None` is returned for unnamed or path-backed sockets.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ pub fn as_abstract(&self) -> Option<&[u8]> {
+ if self.1 >= 1 && self.0.sun_path[0] == 0 {
+ Some(&self.sun_path()[1..])
+ } else {
+ // unnamed or filesystem path
+ None
+ }
+ }
+}
+
+impl PartialEq for UnixAddr {
+ fn eq(&self, other: &UnixAddr) -> bool {
+ self.sun_path() == other.sun_path()
+ }
+}
+
+impl Eq for UnixAddr {
+}
+
+impl hash::Hash for UnixAddr {
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ ( self.0.sun_family, self.sun_path() ).hash(s)
+ }
+}
+
+impl Clone for UnixAddr {
+ fn clone(&self) -> UnixAddr {
+ *self
+ }
+}
+
+impl fmt::Display for UnixAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if self.1 == 0 {
+ f.write_str("<unbound UNIX socket>")
+ } else if let Some(path) = self.path() {
+ path.display().fmt(f)
+ } else {
+ let display = String::from_utf8_lossy(&self.sun_path()[1..]);
+ write!(f, "@{}", display)
+ }
+ }
+}
+
+impl fmt::Debug for UnixAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+/*
+ *
+ * ===== Sock addr =====
+ *
+ */
+
+/// Represents a socket address
+#[derive(Copy, Debug)]
+pub enum SockAddr {
+ Inet(InetAddr),
+ Unix(UnixAddr),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Netlink(NetlinkAddr),
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ SysControl(SysControlAddr),
+ /// Datalink address (MAC)
+ #[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Link(LinkAddr)
+}
+
+impl SockAddr {
+ pub fn new_inet(addr: InetAddr) -> SockAddr {
+ SockAddr::Inet(addr)
+ }
+
+ pub fn new_unix<P: ?Sized + NixPath>(path: &P) -> Result<SockAddr> {
+ Ok(SockAddr::Unix(UnixAddr::new(path)?))
+ }
+
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ pub fn new_netlink(pid: u32, groups: u32) -> SockAddr {
+ SockAddr::Netlink(NetlinkAddr::new(pid, groups))
+ }
+
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ pub fn new_sys_control(sockfd: RawFd, name: &str, unit: u32) -> Result<SockAddr> {
+ SysControlAddr::from_name(sockfd, name, unit).map(|a| SockAddr::SysControl(a))
+ }
+
+ pub fn family(&self) -> AddressFamily {
+ match *self {
+ SockAddr::Inet(InetAddr::V4(..)) => AddressFamily::Inet,
+ SockAddr::Inet(InetAddr::V6(..)) => AddressFamily::Inet6,
+ SockAddr::Unix(..) => AddressFamily::Unix,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ SockAddr::Netlink(..) => AddressFamily::Netlink,
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ SockAddr::SysControl(..) => AddressFamily::System,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ SockAddr::Link(..) => AddressFamily::Packet,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ SockAddr::Link(..) => AddressFamily::Link
+ }
+ }
+
+ pub fn to_str(&self) -> String {
+ format!("{}", self)
+ }
+
+ /// Creates a `SockAddr` struct from libc's sockaddr.
+ ///
+ /// Supports only the following address families: Unix, Inet (v4 & v6), Netlink and System.
+ /// Returns None for unsupported families.
+ pub unsafe fn from_libc_sockaddr(addr: *const libc::sockaddr) -> Option<SockAddr> {
+ if addr.is_null() {
+ None
+ } else {
+ match AddressFamily::from_i32((*addr).sa_family as i32) {
+ Some(AddressFamily::Unix) => None,
+ Some(AddressFamily::Inet) => Some(SockAddr::Inet(
+ InetAddr::V4(*(addr as *const libc::sockaddr_in)))),
+ Some(AddressFamily::Inet6) => Some(SockAddr::Inet(
+ InetAddr::V6(*(addr as *const libc::sockaddr_in6)))),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Some(AddressFamily::Netlink) => Some(SockAddr::Netlink(
+ NetlinkAddr(*(addr as *const libc::sockaddr_nl)))),
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ Some(AddressFamily::System) => Some(SockAddr::SysControl(
+ SysControlAddr(*(addr as *const libc::sockaddr_ctl)))),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Some(AddressFamily::Packet) => Some(SockAddr::Link(
+ LinkAddr(*(addr as *const libc::sockaddr_ll)))),
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ Some(AddressFamily::Link) => {
+ let ether_addr = LinkAddr(*(addr as *const libc::sockaddr_dl));
+ if ether_addr.is_empty() {
+ None
+ } else {
+ Some(SockAddr::Link(ether_addr))
+ }
+ },
+ // Other address families are currently not supported and simply yield a None
+ // entry instead of a proper conversion to a `SockAddr`.
+ Some(_) | None => None,
+ }
+ }
+ }
+
+ /// Conversion from nix's SockAddr type to the underlying libc sockaddr type.
+ ///
+ /// This is useful for interfacing with other libc functions that don't yet have nix wrappers.
+ /// Returns a reference to the underlying data type (as a sockaddr reference) along
+ /// with the size of the actual data type. sockaddr is commonly used as a proxy for
+ /// a superclass as C doesn't support inheritance, so many functions that take
+ /// a sockaddr * need to take the size of the underlying type as well and then internally cast it back.
+ pub unsafe fn as_ffi_pair(&self) -> (&libc::sockaddr, libc::socklen_t) {
+ match *self {
+ SockAddr::Inet(InetAddr::V4(ref addr)) => (mem::transmute(addr), mem::size_of::<libc::sockaddr_in>() as libc::socklen_t),
+ SockAddr::Inet(InetAddr::V6(ref addr)) => (mem::transmute(addr), mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t),
+ SockAddr::Unix(UnixAddr(ref addr, len)) => (mem::transmute(addr), (len + offset_of!(libc::sockaddr_un, sun_path)) as libc::socklen_t),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ SockAddr::Netlink(NetlinkAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t),
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ SockAddr::SysControl(SysControlAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_ctl>() as libc::socklen_t),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ SockAddr::Link(LinkAddr(ref ether_addr)) => (mem::transmute(ether_addr), mem::size_of::<libc::sockaddr_ll>() as libc::socklen_t),
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ SockAddr::Link(LinkAddr(ref ether_addr)) => (mem::transmute(ether_addr), mem::size_of::<libc::sockaddr_dl>() as libc::socklen_t),
+ }
+ }
+}
+
+impl PartialEq for SockAddr {
+ fn eq(&self, other: &SockAddr) -> bool {
+ match (*self, *other) {
+ (SockAddr::Inet(ref a), SockAddr::Inet(ref b)) => {
+ a == b
+ }
+ (SockAddr::Unix(ref a), SockAddr::Unix(ref b)) => {
+ a == b
+ }
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ (SockAddr::Netlink(ref a), SockAddr::Netlink(ref b)) => {
+ a == b
+ }
+ #[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ (SockAddr::Link(ref a), SockAddr::Link(ref b)) => {
+ a == b
+ }
+ _ => false,
+ }
+ }
+}
+
+impl Eq for SockAddr {
+}
+
+impl hash::Hash for SockAddr {
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ match *self {
+ SockAddr::Inet(ref a) => a.hash(s),
+ SockAddr::Unix(ref a) => a.hash(s),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ SockAddr::Netlink(ref a) => a.hash(s),
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ SockAddr::SysControl(ref a) => a.hash(s),
+ #[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ SockAddr::Link(ref ether_addr) => ether_addr.hash(s)
+ }
+ }
+}
+
+impl Clone for SockAddr {
+ fn clone(&self) -> SockAddr {
+ *self
+ }
+}
+
+impl fmt::Display for SockAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ SockAddr::Inet(ref inet) => inet.fmt(f),
+ SockAddr::Unix(ref unix) => unix.fmt(f),
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ SockAddr::Netlink(ref nl) => nl.fmt(f),
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ SockAddr::SysControl(ref sc) => sc.fmt(f),
+ #[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ SockAddr::Link(ref ether_addr) => ether_addr.fmt(f)
+ }
+ }
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub mod netlink {
+ use ::sys::socket::addr::AddressFamily;
+ use libc::{sa_family_t, sockaddr_nl};
+ use std::{fmt, mem};
+ use std::hash::{Hash, Hasher};
+
+ #[derive(Copy, Clone)]
+ pub struct NetlinkAddr(pub sockaddr_nl);
+
+ // , PartialEq, Eq, Debug, Hash
+ impl PartialEq for NetlinkAddr {
+ fn eq(&self, other: &Self) -> bool {
+ let (inner, other) = (self.0, other.0);
+ (inner.nl_family, inner.nl_pid, inner.nl_groups) ==
+ (other.nl_family, other.nl_pid, other.nl_groups)
+ }
+ }
+
+ impl Eq for NetlinkAddr {}
+
+ impl Hash for NetlinkAddr {
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ let inner = self.0;
+ (inner.nl_family, inner.nl_pid, inner.nl_groups).hash(s);
+ }
+ }
+
+
+ impl NetlinkAddr {
+ pub fn new(pid: u32, groups: u32) -> NetlinkAddr {
+ let mut addr: sockaddr_nl = unsafe { mem::zeroed() };
+ addr.nl_family = AddressFamily::Netlink as sa_family_t;
+ addr.nl_pid = pid;
+ addr.nl_groups = groups;
+
+ NetlinkAddr(addr)
+ }
+
+ pub fn pid(&self) -> u32 {
+ self.0.nl_pid
+ }
+
+ pub fn groups(&self) -> u32 {
+ self.0.nl_groups
+ }
+ }
+
+ impl fmt::Display for NetlinkAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "pid: {} groups: {}", self.pid(), self.groups())
+ }
+ }
+
+ impl fmt::Debug for NetlinkAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+ }
+}
+
+#[cfg(any(target_os = "ios", target_os = "macos"))]
+pub mod sys_control {
+ use ::sys::socket::addr::AddressFamily;
+ use libc::{self, c_uchar};
+ use std::{fmt, mem};
+ use std::hash::{Hash, Hasher};
+ use std::os::unix::io::RawFd;
+ use {Errno, Error, Result};
+
+ #[repr(C)]
+ pub struct ctl_ioc_info {
+ pub ctl_id: u32,
+ pub ctl_name: [c_uchar; MAX_KCTL_NAME],
+ }
+
+ const CTL_IOC_MAGIC: u8 = 'N' as u8;
+ const CTL_IOC_INFO: u8 = 3;
+ const MAX_KCTL_NAME: usize = 96;
+
+ ioctl_readwrite!(ctl_info, CTL_IOC_MAGIC, CTL_IOC_INFO, ctl_ioc_info);
+
+ #[derive(Copy, Clone)]
+ #[repr(C)]
+ pub struct SysControlAddr(pub libc::sockaddr_ctl);
+
+ impl PartialEq for SysControlAddr {
+ fn eq(&self, other: &Self) -> bool {
+ let (inner, other) = (self.0, other.0);
+ (inner.sc_id, inner.sc_unit) ==
+ (other.sc_id, other.sc_unit)
+ }
+ }
+
+ impl Eq for SysControlAddr {}
+
+ impl Hash for SysControlAddr {
+ fn hash<H: Hasher>(&self, s: &mut H) {
+ let inner = self.0;
+ (inner.sc_id, inner.sc_unit).hash(s);
+ }
+ }
+
+
+ impl SysControlAddr {
+ pub fn new(id: u32, unit: u32) -> SysControlAddr {
+ let addr = libc::sockaddr_ctl {
+ sc_len: mem::size_of::<libc::sockaddr_ctl>() as c_uchar,
+ sc_family: AddressFamily::System as c_uchar,
+ ss_sysaddr: libc::AF_SYS_CONTROL as u16,
+ sc_id: id,
+ sc_unit: unit,
+ sc_reserved: [0; 5]
+ };
+
+ SysControlAddr(addr)
+ }
+
+ pub fn from_name(sockfd: RawFd, name: &str, unit: u32) -> Result<SysControlAddr> {
+ if name.len() > MAX_KCTL_NAME {
+ return Err(Error::Sys(Errno::ENAMETOOLONG));
+ }
+
+ let mut ctl_name = [0; MAX_KCTL_NAME];
+ ctl_name[..name.len()].clone_from_slice(name.as_bytes());
+ let mut info = ctl_ioc_info { ctl_id: 0, ctl_name: ctl_name };
+
+ unsafe { ctl_info(sockfd, &mut info)?; }
+
+ Ok(SysControlAddr::new(info.ctl_id, unit))
+ }
+
+ pub fn id(&self) -> u32 {
+ self.0.sc_id
+ }
+
+ pub fn unit(&self) -> u32 {
+ self.0.sc_unit
+ }
+ }
+
+ impl fmt::Display for SysControlAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(self, f)
+ }
+ }
+
+ impl fmt::Debug for SysControlAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("SysControlAddr")
+ .field("sc_len", &self.0.sc_len)
+ .field("sc_family", &self.0.sc_family)
+ .field("ss_sysaddr", &self.0.ss_sysaddr)
+ .field("sc_id", &self.0.sc_id)
+ .field("sc_unit", &self.0.sc_unit)
+ .finish()
+ }
+ }
+}
+
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+mod datalink {
+ use super::{libc, hash, fmt, AddressFamily};
+
+ /// Hardware Address
+ #[derive(Clone, Copy)]
+ pub struct LinkAddr(pub libc::sockaddr_ll);
+
+ impl LinkAddr {
+ /// Always AF_PACKET
+ pub fn family(&self) -> AddressFamily {
+ assert_eq!(self.0.sll_family as i32, libc::AF_PACKET);
+ AddressFamily::Packet
+ }
+
+ /// Physical-layer protocol
+ pub fn protocol(&self) -> u16 {
+ self.0.sll_protocol
+ }
+
+ /// Interface number
+ pub fn ifindex(&self) -> usize {
+ self.0.sll_ifindex as usize
+ }
+
+ /// ARP hardware type
+ pub fn hatype(&self) -> u16 {
+ self.0.sll_hatype
+ }
+
+ /// Packet type
+ pub fn pkttype(&self) -> u8 {
+ self.0.sll_pkttype
+ }
+
+ /// Length of MAC address
+ pub fn halen(&self) -> usize {
+ self.0.sll_halen as usize
+ }
+
+ /// Physical-layer address (MAC)
+ pub fn addr(&self) -> [u8; 6] {
+ let a = self.0.sll_addr[0] as u8;
+ let b = self.0.sll_addr[1] as u8;
+ let c = self.0.sll_addr[2] as u8;
+ let d = self.0.sll_addr[3] as u8;
+ let e = self.0.sll_addr[4] as u8;
+ let f = self.0.sll_addr[5] as u8;
+
+ [a, b, c, d, e, f]
+ }
+ }
+
+ impl Eq for LinkAddr {}
+
+ impl PartialEq for LinkAddr {
+ fn eq(&self, other: &Self) -> bool {
+ let (a, b) = (self.0, other.0);
+ (a.sll_family, a.sll_protocol, a.sll_ifindex, a.sll_hatype,
+ a.sll_pkttype, a.sll_halen, a.sll_addr) ==
+ (b.sll_family, b.sll_protocol, b.sll_ifindex, b.sll_hatype,
+ b.sll_pkttype, b.sll_halen, b.sll_addr)
+ }
+ }
+
+ impl hash::Hash for LinkAddr {
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ let a = self.0;
+ (a.sll_family, a.sll_protocol, a.sll_ifindex, a.sll_hatype,
+ a.sll_pkttype, a.sll_halen, a.sll_addr).hash(s);
+ }
+ }
+
+ impl fmt::Display for LinkAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let addr = self.addr();
+ write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
+ addr[0],
+ addr[1],
+ addr[2],
+ addr[3],
+ addr[4],
+ addr[5])
+ }
+ }
+
+ impl fmt::Debug for LinkAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+ }
+}
+
+#[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+mod datalink {
+ use super::{libc, hash, fmt, AddressFamily};
+
+ /// Hardware Address
+ #[derive(Clone, Copy)]
+ pub struct LinkAddr(pub libc::sockaddr_dl);
+
+ impl LinkAddr {
+ /// Total length of sockaddr
+ pub fn len(&self) -> usize {
+ self.0.sdl_len as usize
+ }
+
+ /// always == AF_LINK
+ pub fn family(&self) -> AddressFamily {
+ assert_eq!(self.0.sdl_family as i32, libc::AF_LINK);
+ AddressFamily::Link
+ }
+
+ /// interface index, if != 0, system given index for interface
+ pub fn ifindex(&self) -> usize {
+ self.0.sdl_index as usize
+ }
+
+ /// Datalink type
+ pub fn datalink_type(&self) -> u8 {
+ self.0.sdl_type
+ }
+
+ // MAC address start position
+ pub fn nlen(&self) -> usize {
+ self.0.sdl_nlen as usize
+ }
+
+ /// link level address length
+ pub fn alen(&self) -> usize {
+ self.0.sdl_alen as usize
+ }
+
+ /// link layer selector length
+ pub fn slen(&self) -> usize {
+ self.0.sdl_slen as usize
+ }
+
+ /// if link level address length == 0,
+ /// or `sdl_data` not be larger.
+ pub fn is_empty(&self) -> bool {
+ let nlen = self.nlen();
+ let alen = self.alen();
+ let data_len = self.0.sdl_data.len();
+
+ if alen > 0 && nlen + alen < data_len {
+ false
+ } else {
+ true
+ }
+ }
+
+ /// Physical-layer address (MAC)
+ pub fn addr(&self) -> [u8; 6] {
+ let nlen = self.nlen();
+ let data = self.0.sdl_data;
+
+ assert!(!self.is_empty());
+
+ let a = data[nlen] as u8;
+ let b = data[nlen + 1] as u8;
+ let c = data[nlen + 2] as u8;
+ let d = data[nlen + 3] as u8;
+ let e = data[nlen + 4] as u8;
+ let f = data[nlen + 5] as u8;
+
+ [a, b, c, d, e, f]
+ }
+ }
+
+ impl Eq for LinkAddr {}
+
+ impl PartialEq for LinkAddr {
+ #[cfg(any(target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ fn eq(&self, other: &Self) -> bool {
+ let (a, b) = (self.0, other.0);
+ (a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type,
+ a.sdl_nlen, a.sdl_alen, a.sdl_slen, &a.sdl_data[..]) ==
+ (b.sdl_len, b.sdl_family, b.sdl_index, b.sdl_type,
+ b.sdl_nlen, b.sdl_alen, b.sdl_slen, &b.sdl_data[..])
+ }
+
+ #[cfg(target_os = "dragonfly")]
+ fn eq(&self, other: &Self) -> bool {
+ let (a, b) = (self.0, other.0);
+ (a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type, a.sdl_nlen,
+ a.sdl_alen, a.sdl_slen, a.sdl_data, a.sdl_rcf, a.sdl_route) ==
+ (b.sdl_len, b.sdl_family, b.sdl_index, b.sdl_type, b.sdl_nlen,
+ b.sdl_alen, b.sdl_slen, b.sdl_data, b.sdl_rcf, b.sdl_route)
+ }
+ }
+
+ impl hash::Hash for LinkAddr {
+ #[cfg(any(target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ let a = self.0;
+ (a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type,
+ a.sdl_nlen, a.sdl_alen, a.sdl_slen, &a.sdl_data[..]).hash(s);
+ }
+
+ #[cfg(target_os = "dragonfly")]
+ fn hash<H: hash::Hasher>(&self, s: &mut H) {
+ let a = self.0;
+ (a.sdl_len, a.sdl_family, a.sdl_index, a.sdl_type, a.sdl_nlen,
+ a.sdl_alen, a.sdl_slen, a.sdl_data, a.sdl_rcf, a.sdl_route).hash(s);
+ }
+ }
+
+ impl fmt::Display for LinkAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let addr = self.addr();
+ write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
+ addr[0],
+ addr[1],
+ addr[2],
+ addr[3],
+ addr[4],
+ addr[5])
+ }
+ }
+
+ impl fmt::Debug for LinkAddr {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ use super::*;
+
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ #[test]
+ fn test_macos_loopback_datalink_addr() {
+ let bytes = [20i8, 18, 1, 0, 24, 3, 0, 0, 108, 111, 48, 0, 0, 0, 0, 0];
+ let sa = bytes.as_ptr() as *const libc::sockaddr;
+ let _sock_addr = unsafe { SockAddr::from_libc_sockaddr(sa) };
+ assert!(_sock_addr.is_none());
+ }
+
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ #[test]
+ fn test_macos_tap_datalink_addr() {
+ let bytes = [20i8, 18, 7, 0, 6, 3, 6, 0, 101, 110, 48, 24, 101, -112, -35, 76, -80];
+ let ptr = bytes.as_ptr();
+ let sa = ptr as *const libc::sockaddr;
+ let _sock_addr = unsafe { SockAddr::from_libc_sockaddr(sa) };
+
+ assert!(_sock_addr.is_some());
+
+ let sock_addr = _sock_addr.unwrap();
+
+ assert_eq!(sock_addr.family(), AddressFamily::Link);
+
+ match sock_addr {
+ SockAddr::Link(ether_addr) => {
+ assert_eq!(ether_addr.addr(), [24u8, 101, 144, 221, 76, 176]);
+ },
+ _ => { unreachable!() }
+ };
+ }
+}
diff --git a/third_party/rust/nix/src/sys/socket/mod.rs b/third_party/rust/nix/src/sys/socket/mod.rs
new file mode 100644
index 0000000000..62c0ea7412
--- /dev/null
+++ b/third_party/rust/nix/src/sys/socket/mod.rs
@@ -0,0 +1,1204 @@
+//! Socket interface functions
+//!
+//! [Further reading](http://man7.org/linux/man-pages/man7/socket.7.html)
+use {Error, Result};
+use errno::Errno;
+use libc::{self, c_void, c_int, socklen_t, size_t};
+use std::{fmt, mem, ptr, slice};
+use std::os::unix::io::RawFd;
+use sys::time::TimeVal;
+use sys::uio::IoVec;
+
+mod addr;
+pub mod sockopt;
+
+/*
+ *
+ * ===== Re-exports =====
+ *
+ */
+
+pub use self::addr::{
+ AddressFamily,
+ SockAddr,
+ InetAddr,
+ UnixAddr,
+ IpAddr,
+ Ipv4Addr,
+ Ipv6Addr,
+ LinkAddr,
+};
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub use ::sys::socket::addr::netlink::NetlinkAddr;
+
+pub use libc::{
+ cmsghdr,
+ msghdr,
+ sa_family_t,
+ sockaddr,
+ sockaddr_in,
+ sockaddr_in6,
+ sockaddr_storage,
+ sockaddr_un,
+};
+
+/// These constants are used to specify the communication semantics
+/// when creating a socket with [`socket()`](fn.socket.html)
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+#[repr(i32)]
+pub enum SockType {
+ /// Provides sequenced, reliable, two-way, connection-
+ /// based byte streams. An out-of-band data transmission
+ /// mechanism may be supported.
+ Stream = libc::SOCK_STREAM,
+ /// Supports datagrams (connectionless, unreliable
+ /// messages of a fixed maximum length).
+ Datagram = libc::SOCK_DGRAM,
+ /// Provides a sequenced, reliable, two-way connection-
+ /// based data transmission path for datagrams of fixed
+ /// maximum length; a consumer is required to read an
+ /// entire packet with each input system call.
+ SeqPacket = libc::SOCK_SEQPACKET,
+ /// Provides raw network protocol access.
+ Raw = libc::SOCK_RAW,
+ /// Provides a reliable datagram layer that does not
+ /// guarantee ordering.
+ Rdm = libc::SOCK_RDM,
+}
+
+/// Constants used in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html)
+/// to specify the protocol to use.
+#[repr(i32)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+pub enum SockProtocol {
+ /// TCP protocol ([ip(7)](http://man7.org/linux/man-pages/man7/ip.7.html))
+ Tcp = libc::IPPROTO_TCP,
+ /// UDP protocol ([ip(7)](http://man7.org/linux/man-pages/man7/ip.7.html))
+ Udp = libc::IPPROTO_UDP,
+ /// Allows applications and other KEXTs to be notified when certain kernel events occur
+ /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html))
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ KextEvent = libc::SYSPROTO_EVENT,
+ /// Allows applications to configure and control a KEXT
+ /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html))
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ KextControl = libc::SYSPROTO_CONTROL,
+}
+
+libc_bitflags!{
+ /// Additional socket options
+ pub struct SockFlag: c_int {
+ /// Set non-blocking mode on the new socket
+ #[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ SOCK_NONBLOCK;
+ /// Set close-on-exec on the new descriptor
+ #[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ SOCK_CLOEXEC;
+ /// Return `EPIPE` instead of raising `SIGPIPE`
+ #[cfg(target_os = "netbsd")]
+ SOCK_NOSIGPIPE;
+ /// For domains `AF_INET(6)`, only allow `connect(2)`, `sendto(2)`, or `sendmsg(2)`
+ /// to the DNS port (typically 53)
+ #[cfg(target_os = "openbsd")]
+ SOCK_DNS;
+ }
+}
+
+libc_bitflags!{
+ /// Flags for send/recv and their relatives
+ pub struct MsgFlags: c_int {
+ /// Sends or requests out-of-band data on sockets that support this notion
+ /// (e.g., of type [`Stream`](enum.SockType.html)); the underlying protocol must also
+ /// support out-of-band data.
+ MSG_OOB;
+ /// Peeks at an incoming message. The data is treated as unread and the next
+ /// [`recv()`](fn.recv.html)
+ /// or similar function shall still return this data.
+ MSG_PEEK;
+ /// Enables nonblocking operation; if the operation would block,
+ /// `EAGAIN` or `EWOULDBLOCK` is returned. This provides similar
+ /// behavior to setting the `O_NONBLOCK` flag
+ /// (via the [`fcntl`](../../fcntl/fn.fcntl.html)
+ /// `F_SETFL` operation), but differs in that `MSG_DONTWAIT` is a per-
+ /// call option, whereas `O_NONBLOCK` is a setting on the open file
+ /// description (see [open(2)](http://man7.org/linux/man-pages/man2/open.2.html)),
+ /// which will affect all threads in
+ /// the calling process and as well as other processes that hold
+ /// file descriptors referring to the same open file description.
+ MSG_DONTWAIT;
+ /// Receive flags: Control Data was discarded (buffer too small)
+ MSG_CTRUNC;
+ /// For raw ([`Packet`](addr/enum.AddressFamily.html)), Internet datagram
+ /// (since Linux 2.4.27/2.6.8),
+ /// netlink (since Linux 2.6.22) and UNIX datagram (since Linux 3.4)
+ /// sockets: return the real length of the packet or datagram, even
+ /// when it was longer than the passed buffer. Not implemented for UNIX
+ /// domain ([unix(7)](https://linux.die.net/man/7/unix)) sockets.
+ ///
+ /// For use with Internet stream sockets, see [tcp(7)](https://linux.die.net/man/7/tcp).
+ MSG_TRUNC;
+ /// Terminates a record (when this notion is supported, as for
+ /// sockets of type [`SeqPacket`](enum.SockType.html)).
+ MSG_EOR;
+ /// This flag specifies that queued errors should be received from
+ /// the socket error queue. (For more details, see
+ /// [recvfrom(2)](https://linux.die.net/man/2/recvfrom))
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ MSG_ERRQUEUE;
+ /// Set the `close-on-exec` flag for the file descriptor received via a UNIX domain
+ /// file descriptor using the `SCM_RIGHTS` operation (described in
+ /// [unix(7)](https://linux.die.net/man/7/unix)).
+ /// This flag is useful for the same reasons as the `O_CLOEXEC` flag of
+ /// [open(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html).
+ ///
+ /// Only used in [`recvmsg`](fn.recvmsg.html) function.
+ #[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ MSG_CMSG_CLOEXEC;
+ }
+}
+
+cfg_if! {
+ if #[cfg(any(target_os = "android", target_os = "linux"))] {
+ /// Unix credentials of the sending process.
+ ///
+ /// This struct is used with the `SO_PEERCRED` ancillary message for UNIX sockets.
+ #[repr(C)]
+ #[derive(Clone, Copy)]
+ pub struct UnixCredentials(libc::ucred);
+
+ impl UnixCredentials {
+ /// Returns the process identifier
+ pub fn pid(&self) -> libc::pid_t {
+ self.0.pid
+ }
+
+ /// Returns the user identifier
+ pub fn uid(&self) -> libc::uid_t {
+ self.0.uid
+ }
+
+ /// Returns the group identifier
+ pub fn gid(&self) -> libc::gid_t {
+ self.0.gid
+ }
+ }
+
+ impl PartialEq for UnixCredentials {
+ fn eq(&self, other: &Self) -> bool {
+ self.0.pid == other.0.pid && self.0.uid == other.0.uid && self.0.gid == other.0.gid
+ }
+ }
+ impl Eq for UnixCredentials {}
+
+ impl From<libc::ucred> for UnixCredentials {
+ fn from(cred: libc::ucred) -> Self {
+ UnixCredentials(cred)
+ }
+ }
+
+ impl Into<libc::ucred> for UnixCredentials {
+ fn into(self) -> libc::ucred {
+ self.0
+ }
+ }
+
+ impl fmt::Debug for UnixCredentials {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("UnixCredentials")
+ .field("pid", &self.0.pid)
+ .field("uid", &self.0.uid)
+ .field("gid", &self.0.gid)
+ .finish()
+ }
+ }
+ }
+}
+
+/// Request for multicast socket operations
+///
+/// This is a wrapper type around `ip_mreq`.
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub struct IpMembershipRequest(libc::ip_mreq);
+
+impl IpMembershipRequest {
+ /// Instantiate a new `IpMembershipRequest`
+ ///
+ /// If `interface` is `None`, then `Ipv4Addr::any()` will be used for the interface.
+ pub fn new(group: Ipv4Addr, interface: Option<Ipv4Addr>) -> Self {
+ IpMembershipRequest(libc::ip_mreq {
+ imr_multiaddr: group.0,
+ imr_interface: interface.unwrap_or_else(Ipv4Addr::any).0,
+ })
+ }
+}
+
+impl PartialEq for IpMembershipRequest {
+ fn eq(&self, other: &Self) -> bool {
+ self.0.imr_multiaddr.s_addr == other.0.imr_multiaddr.s_addr
+ && self.0.imr_interface.s_addr == other.0.imr_interface.s_addr
+ }
+}
+impl Eq for IpMembershipRequest {}
+
+impl fmt::Debug for IpMembershipRequest {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mref = &self.0.imr_multiaddr;
+ let maddr = mref.s_addr;
+ let iref = &self.0.imr_interface;
+ let ifaddr = iref.s_addr;
+ f.debug_struct("IpMembershipRequest")
+ .field("imr_multiaddr", &maddr)
+ .field("imr_interface", &ifaddr)
+ .finish()
+ }
+}
+
+/// Request for ipv6 multicast socket operations
+///
+/// This is a wrapper type around `ipv6_mreq`.
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub struct Ipv6MembershipRequest(libc::ipv6_mreq);
+
+impl Ipv6MembershipRequest {
+ /// Instantiate a new `Ipv6MembershipRequest`
+ pub fn new(group: Ipv6Addr) -> Self {
+ Ipv6MembershipRequest(libc::ipv6_mreq {
+ ipv6mr_multiaddr: group.0,
+ ipv6mr_interface: 0,
+ })
+ }
+}
+
+impl PartialEq for Ipv6MembershipRequest {
+ fn eq(&self, other: &Self) -> bool {
+ self.0.ipv6mr_multiaddr.s6_addr == other.0.ipv6mr_multiaddr.s6_addr &&
+ self.0.ipv6mr_interface == other.0.ipv6mr_interface
+ }
+}
+impl Eq for Ipv6MembershipRequest {}
+
+impl fmt::Debug for Ipv6MembershipRequest {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("Ipv6MembershipRequest")
+ .field("ipv6mr_multiaddr", &self.0.ipv6mr_multiaddr.s6_addr)
+ .field("ipv6mr_interface", &self.0.ipv6mr_interface)
+ .finish()
+ }
+}
+
+/// Copy the in-memory representation of `src` into the byte slice `dst`.
+///
+/// Returns the remainder of `dst`.
+///
+/// Panics when `dst` is too small for `src` (more precisely, panics if
+/// `mem::size_of_val(src) >= dst.len()`).
+///
+/// Unsafe because it transmutes `src` to raw bytes, which is only safe for some
+/// types `T`. Refer to the [Rustonomicon] for details.
+///
+/// [Rustonomicon]: https://doc.rust-lang.org/nomicon/transmutes.html
+unsafe fn copy_bytes<'a, T: ?Sized>(src: &T, dst: &'a mut [u8]) -> &'a mut [u8] {
+ let srclen = mem::size_of_val(src);
+ ptr::copy_nonoverlapping(
+ src as *const T as *const u8,
+ dst[..srclen].as_mut_ptr(),
+ srclen
+ );
+
+ &mut dst[srclen..]
+}
+
+/// Fills `dst` with `len` zero bytes and returns the remainder of the slice.
+///
+/// Panics when `len >= dst.len()`.
+fn pad_bytes(len: usize, dst: &mut [u8]) -> &mut [u8] {
+ for pad in &mut dst[..len] {
+ *pad = 0;
+ }
+
+ &mut dst[len..]
+}
+
+cfg_if! {
+ // Darwin and DragonFly BSD always align struct cmsghdr to 32-bit only.
+ if #[cfg(any(target_os = "dragonfly", target_os = "ios", target_os = "macos"))] {
+ type align_of_cmsg_data = u32;
+ } else {
+ type align_of_cmsg_data = size_t;
+ }
+}
+
+/// A structure used to make room in a cmsghdr passed to recvmsg. The
+/// size and alignment match that of a cmsghdr followed by a T, but the
+/// fields are not accessible, as the actual types will change on a call
+/// to recvmsg.
+///
+/// To make room for multiple messages, nest the type parameter with
+/// tuples:
+///
+/// ```
+/// use std::os::unix::io::RawFd;
+/// use nix::sys::socket::CmsgSpace;
+/// let cmsg: CmsgSpace<([RawFd; 3], CmsgSpace<[RawFd; 2]>)> = CmsgSpace::new();
+/// ```
+#[repr(C)]
+#[allow(missing_debug_implementations)]
+pub struct CmsgSpace<T> {
+ _hdr: cmsghdr,
+ _pad: [align_of_cmsg_data; 0],
+ _data: T,
+}
+
+impl<T> CmsgSpace<T> {
+ /// Create a CmsgSpace<T>. The structure is used only for space, so
+ /// the fields are uninitialized.
+ pub fn new() -> Self {
+ // Safe because the fields themselves aren't accessible.
+ unsafe { mem::uninitialized() }
+ }
+}
+
+#[derive(Debug)]
+pub struct RecvMsg<'a> {
+ // The number of bytes received.
+ pub bytes: usize,
+ cmsg_buffer: &'a [u8],
+ pub address: Option<SockAddr>,
+ pub flags: MsgFlags,
+}
+
+impl<'a> RecvMsg<'a> {
+ /// Iterate over the valid control messages pointed to by this
+ /// msghdr.
+ pub fn cmsgs(&self) -> CmsgIterator {
+ CmsgIterator {
+ buf: self.cmsg_buffer,
+ }
+ }
+}
+
+#[derive(Debug)]
+pub struct CmsgIterator<'a> {
+ /// Control message buffer to decode from. Must adhere to cmsg alignment.
+ buf: &'a [u8],
+}
+
+impl<'a> Iterator for CmsgIterator<'a> {
+ type Item = ControlMessage<'a>;
+
+ // The implementation loosely follows CMSG_FIRSTHDR / CMSG_NXTHDR,
+ // although we handle the invariants in slightly different places to
+ // get a better iterator interface.
+ fn next(&mut self) -> Option<ControlMessage<'a>> {
+ if self.buf.len() == 0 {
+ // The iterator assumes that `self.buf` always contains exactly the
+ // bytes we need, so we're at the end when the buffer is empty.
+ return None;
+ }
+
+ // Safe if: `self.buf` is `cmsghdr`-aligned.
+ let cmsg: &'a cmsghdr = unsafe {
+ &*(self.buf[..mem::size_of::<cmsghdr>()].as_ptr() as *const cmsghdr)
+ };
+
+ let cmsg_len = cmsg.cmsg_len as usize;
+
+ // Advance our internal pointer.
+ let cmsg_data = &self.buf[cmsg_align(mem::size_of::<cmsghdr>())..cmsg_len];
+ self.buf = &self.buf[cmsg_align(cmsg_len)..];
+
+ // Safe if: `cmsg_data` contains the expected (amount of) content. This
+ // is verified by the kernel.
+ unsafe {
+ Some(ControlMessage::decode_from(cmsg, cmsg_data))
+ }
+ }
+}
+
+/// A type-safe wrapper around a single control message. More types may
+/// be added to this enum; do not exhaustively pattern-match it.
+/// [Further reading](http://man7.org/linux/man-pages/man3/cmsg.3.html)
+#[allow(missing_debug_implementations)]
+pub enum ControlMessage<'a> {
+ /// A message of type `SCM_RIGHTS`, containing an array of file
+ /// descriptors passed between processes.
+ ///
+ /// See the description in the "Ancillary messages" section of the
+ /// [unix(7) man page](http://man7.org/linux/man-pages/man7/unix.7.html).
+ ///
+ /// Using multiple `ScmRights` messages for a single `sendmsg` call isn't recommended since it
+ /// causes platform-dependent behaviour: It might swallow all but the first `ScmRights` message
+ /// or fail with `EINVAL`. Instead, you can put all fds to be passed into a single `ScmRights`
+ /// message.
+ ScmRights(&'a [RawFd]),
+ /// A message of type `SCM_CREDENTIALS`, containing the pid, uid and gid of
+ /// a process connected to the socket.
+ ///
+ /// This is similar to the socket option `SO_PEERCRED`, but requires a
+ /// process to explicitly send its credentials. A process running as root is
+ /// allowed to specify any credentials, while credentials sent by other
+ /// processes are verified by the kernel.
+ ///
+ /// For further information, please refer to the
+ /// [`unix(7)`](http://man7.org/linux/man-pages/man7/unix.7.html) man page.
+ // FIXME: When `#[repr(transparent)]` is stable, use it on `UnixCredentials`
+ // and put that in here instead of a raw ucred.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ ScmCredentials(&'a libc::ucred),
+ /// A message of type `SCM_TIMESTAMP`, containing the time the
+ /// packet was received by the kernel.
+ ///
+ /// See the kernel's explanation in "SO_TIMESTAMP" of
+ /// [networking/timestamping](https://www.kernel.org/doc/Documentation/networking/timestamping.txt).
+ ///
+ /// # Examples
+ ///
+ // Disable this test on FreeBSD i386
+ // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=222039
+ #[cfg_attr(not(all(target_os = "freebsd", target_arch = "x86")), doc = " ```")]
+ #[cfg_attr(all(target_os = "freebsd", target_arch = "x86"), doc = " ```no_run")]
+ /// use nix::sys::socket::*;
+ /// use nix::sys::uio::IoVec;
+ /// use nix::sys::time::*;
+ /// use std::time::*;
+ ///
+ /// // Set up
+ /// let message = "Ohayō!".as_bytes();
+ /// let in_socket = socket(
+ /// AddressFamily::Inet,
+ /// SockType::Datagram,
+ /// SockFlag::empty(),
+ /// None).unwrap();
+ /// setsockopt(in_socket, sockopt::ReceiveTimestamp, &true).unwrap();
+ /// let localhost = InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0);
+ /// bind(in_socket, &SockAddr::new_inet(localhost)).unwrap();
+ /// let address = getsockname(in_socket).unwrap();
+ /// // Get initial time
+ /// let time0 = SystemTime::now();
+ /// // Send the message
+ /// let iov = [IoVec::from_slice(message)];
+ /// let flags = MsgFlags::empty();
+ /// let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap();
+ /// assert_eq!(message.len(), l);
+ /// // Receive the message
+ /// let mut buffer = vec![0u8; message.len()];
+ /// let mut cmsgspace: CmsgSpace<TimeVal> = CmsgSpace::new();
+ /// let iov = [IoVec::from_mut_slice(&mut buffer)];
+ /// let r = recvmsg(in_socket, &iov, Some(&mut cmsgspace), flags).unwrap();
+ /// let rtime = match r.cmsgs().next() {
+ /// Some(ControlMessage::ScmTimestamp(&rtime)) => rtime,
+ /// Some(_) => panic!("Unexpected control message"),
+ /// None => panic!("No control message")
+ /// };
+ /// // Check the final time
+ /// let time1 = SystemTime::now();
+ /// // the packet's received timestamp should lie in-between the two system
+ /// // times, unless the system clock was adjusted in the meantime.
+ /// let rduration = Duration::new(rtime.tv_sec() as u64,
+ /// rtime.tv_usec() as u32 * 1000);
+ /// assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration);
+ /// assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap());
+ /// // Close socket
+ /// nix::unistd::close(in_socket).unwrap();
+ /// ```
+ ScmTimestamp(&'a TimeVal),
+
+ #[cfg(any(
+ target_os = "android",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ Ipv4PacketInfo(&'a libc::in_pktinfo),
+ #[cfg(any(
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ Ipv6PacketInfo(&'a libc::in6_pktinfo),
+
+ /// Catch-all variant for unimplemented cmsg types.
+ #[doc(hidden)]
+ Unknown(UnknownCmsg<'a>),
+}
+
+// An opaque structure used to prevent cmsghdr from being a public type
+#[doc(hidden)]
+#[allow(missing_debug_implementations)]
+pub struct UnknownCmsg<'a>(&'a cmsghdr, &'a [u8]);
+
+// Round `len` up to meet the platform's required alignment for
+// `cmsghdr`s and trailing `cmsghdr` data. This should match the
+// behaviour of CMSG_ALIGN from the Linux headers and do the correct
+// thing on other platforms that don't usually provide CMSG_ALIGN.
+#[inline]
+fn cmsg_align(len: usize) -> usize {
+ let align_bytes = mem::size_of::<align_of_cmsg_data>() - 1;
+ (len + align_bytes) & !align_bytes
+}
+
+impl<'a> ControlMessage<'a> {
+ /// The value of CMSG_SPACE on this message.
+ fn space(&self) -> usize {
+ cmsg_align(self.len())
+ }
+
+ /// The value of CMSG_LEN on this message.
+ fn len(&self) -> usize {
+ cmsg_align(mem::size_of::<cmsghdr>()) + match *self {
+ ControlMessage::ScmRights(fds) => {
+ mem::size_of_val(fds)
+ },
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ ControlMessage::ScmCredentials(creds) => {
+ mem::size_of_val(creds)
+ }
+ ControlMessage::ScmTimestamp(t) => {
+ mem::size_of_val(t)
+ },
+ #[cfg(any(
+ target_os = "android",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ ControlMessage::Ipv4PacketInfo(pktinfo) => {
+ mem::size_of_val(pktinfo)
+ },
+ #[cfg(any(
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ ControlMessage::Ipv6PacketInfo(pktinfo) => {
+ mem::size_of_val(pktinfo)
+ },
+ ControlMessage::Unknown(UnknownCmsg(_, bytes)) => {
+ mem::size_of_val(bytes)
+ }
+ }
+ }
+
+ /// Returns the value to put into the `cmsg_level` field of the header.
+ fn cmsg_level(&self) -> libc::c_int {
+ match *self {
+ ControlMessage::ScmRights(_) => libc::SOL_SOCKET,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET,
+ ControlMessage::ScmTimestamp(_) => libc::SOL_SOCKET,
+ #[cfg(any(
+ target_os = "android",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ ControlMessage::Ipv4PacketInfo(_) => libc::IPPROTO_IP,
+ #[cfg(any(
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6,
+ ControlMessage::Unknown(ref cmsg) => cmsg.0.cmsg_level,
+ }
+ }
+
+ /// Returns the value to put into the `cmsg_type` field of the header.
+ fn cmsg_type(&self) -> libc::c_int {
+ match *self {
+ ControlMessage::ScmRights(_) => libc::SCM_RIGHTS,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS,
+ ControlMessage::ScmTimestamp(_) => libc::SCM_TIMESTAMP,
+ #[cfg(any(
+ target_os = "android",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ ControlMessage::Ipv4PacketInfo(_) => libc::IP_PKTINFO,
+ #[cfg(any(
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ ControlMessage::Ipv6PacketInfo(_) => libc::IPV6_PKTINFO,
+ ControlMessage::Unknown(ref cmsg) => cmsg.0.cmsg_type,
+ }
+ }
+
+ // Unsafe: start and end of buffer must be cmsg_align'd. Updates
+ // the provided slice; panics if the buffer is too small.
+ unsafe fn encode_into(&self, buf: &mut [u8]) {
+ let final_buf = if let ControlMessage::Unknown(ref cmsg) = *self {
+ let &UnknownCmsg(orig_cmsg, bytes) = cmsg;
+
+ let buf = copy_bytes(orig_cmsg, buf);
+
+ let padlen = cmsg_align(mem::size_of_val(&orig_cmsg)) -
+ mem::size_of_val(&orig_cmsg);
+ let buf = pad_bytes(padlen, buf);
+
+ copy_bytes(bytes, buf)
+ } else {
+ let cmsg = cmsghdr {
+ cmsg_len: self.len() as _,
+ cmsg_level: self.cmsg_level(),
+ cmsg_type: self.cmsg_type(),
+ ..mem::zeroed() // zero out platform-dependent padding fields
+ };
+ let buf = copy_bytes(&cmsg, buf);
+
+ let padlen = cmsg_align(mem::size_of_val(&cmsg)) -
+ mem::size_of_val(&cmsg);
+ let buf = pad_bytes(padlen, buf);
+
+ match *self {
+ ControlMessage::ScmRights(fds) => {
+ copy_bytes(fds, buf)
+ },
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ ControlMessage::ScmCredentials(creds) => {
+ copy_bytes(creds, buf)
+ },
+ ControlMessage::ScmTimestamp(t) => {
+ copy_bytes(t, buf)
+ },
+ #[cfg(any(
+ target_os = "android",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ ControlMessage::Ipv4PacketInfo(pktinfo) => {
+ copy_bytes(pktinfo, buf)
+ },
+ #[cfg(any(
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ ControlMessage::Ipv6PacketInfo(pktinfo) => {
+ copy_bytes(pktinfo, buf)
+ }
+ ControlMessage::Unknown(_) => unreachable!(),
+ }
+ };
+
+ let padlen = self.space() - self.len();
+ pad_bytes(padlen, final_buf);
+ }
+
+ /// Decodes a `ControlMessage` from raw bytes.
+ ///
+ /// This is only safe to call if the data is correct for the message type
+ /// specified in the header. Normally, the kernel ensures that this is the
+ /// case. "Correct" in this case includes correct length, alignment and
+ /// actual content.
+ unsafe fn decode_from(header: &'a cmsghdr, data: &'a [u8]) -> ControlMessage<'a> {
+ match (header.cmsg_level, header.cmsg_type) {
+ (libc::SOL_SOCKET, libc::SCM_RIGHTS) => {
+ ControlMessage::ScmRights(
+ slice::from_raw_parts(data.as_ptr() as *const _,
+ data.len() / mem::size_of::<RawFd>()))
+ },
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ (libc::SOL_SOCKET, libc::SCM_CREDENTIALS) => {
+ ControlMessage::ScmCredentials(
+ &*(data.as_ptr() as *const _)
+ )
+ }
+ (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => {
+ ControlMessage::ScmTimestamp(
+ &*(data.as_ptr() as *const _))
+ },
+ #[cfg(any(
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => {
+ ControlMessage::Ipv6PacketInfo(
+ &*(data.as_ptr() as *const _))
+ }
+ #[cfg(any(
+ target_os = "android",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+ ))]
+ (libc::IPPROTO_IP, libc::IP_PKTINFO) => {
+ ControlMessage::Ipv4PacketInfo(
+ &*(data.as_ptr() as *const _))
+ }
+
+ (_, _) => {
+ ControlMessage::Unknown(UnknownCmsg(header, data))
+ }
+ }
+ }
+}
+
+
+/// Send data in scatter-gather vectors to a socket, possibly accompanied
+/// by ancillary data. Optionally direct the message at the given address,
+/// as with sendto.
+///
+/// Allocates if cmsgs is nonempty.
+pub fn sendmsg<'a>(fd: RawFd, iov: &[IoVec<&'a [u8]>], cmsgs: &[ControlMessage<'a>], flags: MsgFlags, addr: Option<&'a SockAddr>) -> Result<usize> {
+ let mut capacity = 0;
+ for cmsg in cmsgs {
+ capacity += cmsg.space();
+ }
+ // Note that the resulting vector claims to have length == capacity,
+ // so it's presently uninitialized.
+ let mut cmsg_buffer = unsafe {
+ let mut vec = Vec::<u8>::with_capacity(capacity);
+ vec.set_len(capacity);
+ vec
+ };
+ {
+ let mut ofs = 0;
+ for cmsg in cmsgs {
+ let ptr = &mut cmsg_buffer[ofs..];
+ unsafe {
+ cmsg.encode_into(ptr);
+ }
+ ofs += cmsg.space();
+ }
+ }
+
+ let (name, namelen) = match addr {
+ Some(addr) => { let (x, y) = unsafe { addr.as_ffi_pair() }; (x as *const _, y) }
+ None => (ptr::null(), 0),
+ };
+
+ let cmsg_ptr = if capacity > 0 {
+ cmsg_buffer.as_ptr() as *const c_void
+ } else {
+ ptr::null()
+ };
+
+ let mhdr = unsafe {
+ let mut mhdr: msghdr = mem::uninitialized();
+ mhdr.msg_name = name as *mut _;
+ mhdr.msg_namelen = namelen;
+ mhdr.msg_iov = iov.as_ptr() as *mut _;
+ mhdr.msg_iovlen = iov.len() as _;
+ mhdr.msg_control = cmsg_ptr as *mut _;
+ mhdr.msg_controllen = capacity as _;
+ mhdr.msg_flags = 0;
+ mhdr
+ };
+ let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) };
+
+ Errno::result(ret).map(|r| r as usize)
+}
+
+/// Receive message in scatter-gather vectors from a socket, and
+/// optionally receive ancillary data into the provided buffer.
+/// If no ancillary data is desired, use () as the type parameter.
+pub fn recvmsg<'a, T>(fd: RawFd, iov: &[IoVec<&mut [u8]>], cmsg_buffer: Option<&'a mut CmsgSpace<T>>, flags: MsgFlags) -> Result<RecvMsg<'a>> {
+ let mut address: sockaddr_storage = unsafe { mem::uninitialized() };
+ let (msg_control, msg_controllen) = match cmsg_buffer {
+ Some(cmsg_buffer) => (cmsg_buffer as *mut _, mem::size_of_val(cmsg_buffer)),
+ None => (ptr::null_mut(), 0),
+ };
+ let mut mhdr = unsafe {
+ let mut mhdr: msghdr = mem::uninitialized();
+ mhdr.msg_name = &mut address as *mut _ as *mut _;
+ mhdr.msg_namelen = mem::size_of::<sockaddr_storage>() as socklen_t;
+ mhdr.msg_iov = iov.as_ptr() as *mut _;
+ mhdr.msg_iovlen = iov.len() as _;
+ mhdr.msg_control = msg_control as *mut _;
+ mhdr.msg_controllen = msg_controllen as _;
+ mhdr.msg_flags = 0;
+ mhdr
+ };
+ let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) };
+
+ let cmsg_buffer = if msg_controllen > 0 {
+ // got control message(s)
+ debug_assert!(!mhdr.msg_control.is_null());
+ unsafe {
+ // Safe: The pointer is not null and the length is correct as part of `recvmsg`s
+ // contract.
+ slice::from_raw_parts(mhdr.msg_control as *const u8,
+ mhdr.msg_controllen as usize)
+ }
+ } else {
+ // No control message, create an empty buffer to avoid creating a slice from a null pointer
+ &[]
+ };
+
+ Ok(unsafe { RecvMsg {
+ bytes: Errno::result(ret)? as usize,
+ cmsg_buffer,
+ address: sockaddr_storage_to_addr(&address,
+ mhdr.msg_namelen as usize).ok(),
+ flags: MsgFlags::from_bits_truncate(mhdr.msg_flags),
+ } })
+}
+
+
+/// Create an endpoint for communication
+///
+/// The `protocol` specifies a particular protocol to be used with the
+/// socket. Normally only a single protocol exists to support a
+/// particular socket type within a given protocol family, in which case
+/// protocol can be specified as `None`. However, it is possible that many
+/// protocols may exist, in which case a particular protocol must be
+/// specified in this manner.
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html)
+pub fn socket<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, flags: SockFlag, protocol: T) -> Result<RawFd> {
+ let protocol = match protocol.into() {
+ None => 0,
+ Some(p) => p as c_int,
+ };
+
+ // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a
+ // little easier to understand by separating it out. So we have to merge these bitfields
+ // here.
+ let mut ty = ty as c_int;
+ ty |= flags.bits();
+
+ let res = unsafe { libc::socket(domain as c_int, ty, protocol) };
+
+ Errno::result(res)
+}
+
+/// Create a pair of connected sockets
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html)
+pub fn socketpair<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, protocol: T,
+ flags: SockFlag) -> Result<(RawFd, RawFd)> {
+ let protocol = match protocol.into() {
+ None => 0,
+ Some(p) => p as c_int,
+ };
+
+ // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a
+ // little easier to understand by separating it out. So we have to merge these bitfields
+ // here.
+ let mut ty = ty as c_int;
+ ty |= flags.bits();
+
+ let mut fds = [-1, -1];
+
+ let res = unsafe { libc::socketpair(domain as c_int, ty, protocol, fds.as_mut_ptr()) };
+ Errno::result(res)?;
+
+ Ok((fds[0], fds[1]))
+}
+
+/// Listen for connections on a socket
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html)
+pub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> {
+ let res = unsafe { libc::listen(sockfd, backlog as c_int) };
+
+ Errno::result(res).map(drop)
+}
+
+/// Bind a name to a socket
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html)
+pub fn bind(fd: RawFd, addr: &SockAddr) -> Result<()> {
+ let res = unsafe {
+ let (ptr, len) = addr.as_ffi_pair();
+ libc::bind(fd, ptr, len)
+ };
+
+ Errno::result(res).map(drop)
+}
+
+/// Accept a connection on a socket
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html)
+pub fn accept(sockfd: RawFd) -> Result<RawFd> {
+ let res = unsafe { libc::accept(sockfd, ptr::null_mut(), ptr::null_mut()) };
+
+ Errno::result(res)
+}
+
+/// Accept a connection on a socket
+///
+/// [Further reading](http://man7.org/linux/man-pages/man2/accept.2.html)
+#[cfg(any(target_os = "android",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "openbsd"))]
+pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> {
+ let res = unsafe { libc::accept4(sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits()) };
+
+ Errno::result(res)
+}
+
+/// Initiate a connection on a socket
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html)
+pub fn connect(fd: RawFd, addr: &SockAddr) -> Result<()> {
+ let res = unsafe {
+ let (ptr, len) = addr.as_ffi_pair();
+ libc::connect(fd, ptr, len)
+ };
+
+ Errno::result(res).map(drop)
+}
+
+/// Receive data from a connection-oriented socket. Returns the number of
+/// bytes read
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html)
+pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> {
+ unsafe {
+ let ret = libc::recv(
+ sockfd,
+ buf.as_ptr() as *mut c_void,
+ buf.len() as size_t,
+ flags.bits());
+
+ Errno::result(ret).map(|r| r as usize)
+ }
+}
+
+/// Receive data from a connectionless or connection-oriented socket. Returns
+/// the number of bytes read and the socket address of the sender.
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html)
+pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) -> Result<(usize, SockAddr)> {
+ unsafe {
+ let addr: sockaddr_storage = mem::zeroed();
+ let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
+
+ let ret = Errno::result(libc::recvfrom(
+ sockfd,
+ buf.as_ptr() as *mut c_void,
+ buf.len() as size_t,
+ 0,
+ mem::transmute(&addr),
+ &mut len as *mut socklen_t))?;
+
+ sockaddr_storage_to_addr(&addr, len as usize)
+ .map(|addr| (ret as usize, addr))
+ }
+}
+
+/// Send a message to a socket
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html)
+pub fn sendto(fd: RawFd, buf: &[u8], addr: &SockAddr, flags: MsgFlags) -> Result<usize> {
+ let ret = unsafe {
+ let (ptr, len) = addr.as_ffi_pair();
+ libc::sendto(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits(), ptr, len)
+ };
+
+ Errno::result(ret).map(|r| r as usize)
+}
+
+/// Send data to a connection-oriented socket. Returns the number of bytes read
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html)
+pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize> {
+ let ret = unsafe {
+ libc::send(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits())
+ };
+
+ Errno::result(ret).map(|r| r as usize)
+}
+
+/*
+ *
+ * ===== Socket Options =====
+ *
+ */
+
+/// The protocol level at which to get / set socket options. Used as an
+/// argument to `getsockopt` and `setsockopt`.
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html)
+#[repr(i32)]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+pub enum SockLevel {
+ Socket = libc::SOL_SOCKET,
+ Tcp = libc::IPPROTO_TCP,
+ Ip = libc::IPPROTO_IP,
+ Ipv6 = libc::IPPROTO_IPV6,
+ Udp = libc::IPPROTO_UDP,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ Netlink = libc::SOL_NETLINK,
+}
+
+/// Represents a socket option that can be accessed or set. Used as an argument
+/// to `getsockopt`
+pub trait GetSockOpt : Copy {
+ type Val;
+
+ #[doc(hidden)]
+ fn get(&self, fd: RawFd) -> Result<Self::Val>;
+}
+
+/// Represents a socket option that can be accessed or set. Used as an argument
+/// to `setsockopt`
+pub trait SetSockOpt : Copy {
+ type Val;
+
+ #[doc(hidden)]
+ fn set(&self, fd: RawFd, val: &Self::Val) -> Result<()>;
+}
+
+/// Get the current value for the requested socket option
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html)
+pub fn getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val> {
+ opt.get(fd)
+}
+
+/// Sets the value for the requested socket option
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html)
+///
+/// # Examples
+///
+/// ```
+/// use nix::sys::socket::setsockopt;
+/// use nix::sys::socket::sockopt::KeepAlive;
+/// use std::net::TcpListener;
+/// use std::os::unix::io::AsRawFd;
+///
+/// let listener = TcpListener::bind("0.0.0.0:0").unwrap();
+/// let fd = listener.as_raw_fd();
+/// let res = setsockopt(fd, KeepAlive, &true);
+/// assert!(res.is_ok());
+/// ```
+pub fn setsockopt<O: SetSockOpt>(fd: RawFd, opt: O, val: &O::Val) -> Result<()> {
+ opt.set(fd, val)
+}
+
+/// Get the address of the peer connected to the socket `fd`.
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html)
+pub fn getpeername(fd: RawFd) -> Result<SockAddr> {
+ unsafe {
+ let addr: sockaddr_storage = mem::uninitialized();
+ let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
+
+ let ret = libc::getpeername(fd, mem::transmute(&addr), &mut len);
+
+ Errno::result(ret)?;
+
+ sockaddr_storage_to_addr(&addr, len as usize)
+ }
+}
+
+/// Get the current address to which the socket `fd` is bound.
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html)
+pub fn getsockname(fd: RawFd) -> Result<SockAddr> {
+ unsafe {
+ let addr: sockaddr_storage = mem::uninitialized();
+ let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
+
+ let ret = libc::getsockname(fd, mem::transmute(&addr), &mut len);
+
+ Errno::result(ret)?;
+
+ sockaddr_storage_to_addr(&addr, len as usize)
+ }
+}
+
+/// Return the appropriate `SockAddr` type from a `sockaddr_storage` of a certain
+/// size. In C this would usually be done by casting. The `len` argument
+/// should be the number of bytes in the `sockaddr_storage` that are actually
+/// allocated and valid. It must be at least as large as all the useful parts
+/// of the structure. Note that in the case of a `sockaddr_un`, `len` need not
+/// include the terminating null.
+pub unsafe fn sockaddr_storage_to_addr(
+ addr: &sockaddr_storage,
+ len: usize) -> Result<SockAddr> {
+
+ if len < mem::size_of_val(&addr.ss_family) {
+ return Err(Error::Sys(Errno::ENOTCONN));
+ }
+
+ match addr.ss_family as c_int {
+ libc::AF_INET => {
+ assert!(len as usize == mem::size_of::<sockaddr_in>());
+ let ret = *(addr as *const _ as *const sockaddr_in);
+ Ok(SockAddr::Inet(InetAddr::V4(ret)))
+ }
+ libc::AF_INET6 => {
+ assert!(len as usize == mem::size_of::<sockaddr_in6>());
+ Ok(SockAddr::Inet(InetAddr::V6(*(addr as *const _ as *const sockaddr_in6))))
+ }
+ libc::AF_UNIX => {
+ let sun = *(addr as *const _ as *const sockaddr_un);
+ let pathlen = len - offset_of!(sockaddr_un, sun_path);
+ Ok(SockAddr::Unix(UnixAddr(sun, pathlen)))
+ }
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ libc::AF_NETLINK => {
+ use libc::sockaddr_nl;
+ Ok(SockAddr::Netlink(NetlinkAddr(*(addr as *const _ as *const sockaddr_nl))))
+ }
+ af => panic!("unexpected address family {}", af),
+ }
+}
+
+
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+pub enum Shutdown {
+ /// Further receptions will be disallowed.
+ Read,
+ /// Further transmissions will be disallowed.
+ Write,
+ /// Further receptions and transmissions will be disallowed.
+ Both,
+}
+
+/// Shut down part of a full-duplex connection.
+///
+/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html)
+pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> {
+ unsafe {
+ use libc::shutdown;
+
+ let how = match how {
+ Shutdown::Read => libc::SHUT_RD,
+ Shutdown::Write => libc::SHUT_WR,
+ Shutdown::Both => libc::SHUT_RDWR,
+ };
+
+ Errno::result(shutdown(df, how)).map(drop)
+ }
+}
diff --git a/third_party/rust/nix/src/sys/socket/sockopt.rs b/third_party/rust/nix/src/sys/socket/sockopt.rs
new file mode 100644
index 0000000000..6c5f450dff
--- /dev/null
+++ b/third_party/rust/nix/src/sys/socket/sockopt.rs
@@ -0,0 +1,631 @@
+use super::{GetSockOpt, SetSockOpt};
+use Result;
+use errno::Errno;
+use sys::time::TimeVal;
+use libc::{self, c_int, c_void, socklen_t};
+use std::mem;
+use std::os::unix::io::RawFd;
+use std::ffi::{OsStr, OsString};
+#[cfg(target_family = "unix")]
+use std::os::unix::ffi::OsStrExt;
+
+// Constants
+// TCP_CA_NAME_MAX isn't defined in user space include files
+#[cfg(any(target_os = "freebsd", target_os = "linux"))]
+const TCP_CA_NAME_MAX: usize = 16;
+
+/// Helper for implementing `SetSockOpt` for a given socket option. See
+/// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html).
+///
+/// This macro aims to help implementing `SetSockOpt` for different socket options that accept
+/// different kinds of data to be used with `setsockopt`.
+///
+/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option
+/// you are implementing represents a simple type.
+///
+/// # Arguments
+///
+/// * `$name:ident`: name of the type you want to implement `SetSockOpt` for.
+/// * `$level:path` : socket layer, or a `protocol level`: could be *raw sockets*
+/// (`libc::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),
+/// and more. Please refer to your system manual for more options. Will be passed as the second
+/// argument (`level`) to the `setsockopt` call.
+/// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
+/// `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`)
+/// to the `setsockopt` call.
+/// * Type of the value that you are going to set.
+/// * Type that implements the `Set` trait for the type from the previous item (like `SetBool` for
+/// `bool`, `SetUsize` for `usize`, etc.).
+macro_rules! setsockopt_impl {
+ ($name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
+ impl SetSockOpt for $name {
+ type Val = $ty;
+
+ fn set(&self, fd: RawFd, val: &$ty) -> Result<()> {
+ unsafe {
+ let setter: $setter = Set::new(val);
+
+ let res = libc::setsockopt(fd, $level, $flag,
+ setter.ffi_ptr(),
+ setter.ffi_len());
+ Errno::result(res).map(drop)
+ }
+ }
+ }
+ }
+}
+
+/// Helper for implementing `GetSockOpt` for a given socket option. See
+/// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html).
+///
+/// This macro aims to help implementing `GetSockOpt` for different socket options that accept
+/// different kinds of data to be use with `getsockopt`.
+///
+/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option
+/// you are implementing represents a simple type.
+///
+/// # Arguments
+///
+/// * Name of the type you want to implement `GetSockOpt` for.
+/// * Socket layer, or a `protocol level`: could be *raw sockets* (`lic::SOL_SOCKET`), *ip
+/// protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`), and more. Please refer
+/// to your system manual for more options. Will be passed as the second argument (`level`) to
+/// the `getsockopt` call.
+/// * A flag to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
+/// `libc::SO_ORIGINAL_DST` and others. Will be passed as the third argument (`option_name`) to
+/// the `getsockopt` call.
+/// * Type of the value that you are going to get.
+/// * Type that implements the `Get` trait for the type from the previous item (`GetBool` for
+/// `bool`, `GetUsize` for `usize`, etc.).
+macro_rules! getsockopt_impl {
+ ($name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
+ impl GetSockOpt for $name {
+ type Val = $ty;
+
+ fn get(&self, fd: RawFd) -> Result<$ty> {
+ unsafe {
+ let mut getter: $getter = Get::blank();
+
+ let res = libc::getsockopt(fd, $level, $flag,
+ getter.ffi_ptr(),
+ getter.ffi_len());
+ Errno::result(res)?;
+
+ Ok(getter.unwrap())
+ }
+ }
+ }
+ }
+}
+
+/// Helper to generate the sockopt accessors. See
+/// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html) and
+/// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html).
+///
+/// This macro aims to help implementing `GetSockOpt` and `SetSockOpt` for different socket options
+/// that accept different kinds of data to be use with `getsockopt` and `setsockopt` respectively.
+///
+/// Basically this macro wraps up the [`getsockopt_impl!`](macro.getsockopt_impl.html) and
+/// [`setsockopt_impl!`](macro.setsockopt_impl.html) macros.
+///
+/// # Arguments
+///
+/// * `GetOnly`, `SetOnly` or `Both`: whether you want to implement only getter, only setter or
+/// both of them.
+/// * `$name:ident`: name of type `GetSockOpt`/`SetSockOpt` will be implemented for.
+/// * `$level:path` : socket layer, or a `protocol level`: could be *raw sockets*
+/// (`lic::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),
+/// and more. Please refer to your system manual for more options. Will be passed as the second
+/// argument (`level`) to the `getsockopt`/`setsockopt` call.
+/// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
+/// `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`)
+/// to the `setsockopt`/`getsockopt` call.
+/// * `$ty:ty`: type of the value that will be get/set.
+/// * `$getter:ty`: `Get` implementation; optional; only for `GetOnly` and `Both`.
+/// * `$setter:ty`: `Set` implementation; optional; only for `SetOnly` and `Both`.
+macro_rules! sockopt_impl {
+ (GetOnly, $name:ident, $level:path, $flag:path, bool) => {
+ sockopt_impl!(GetOnly, $name, $level, $flag, bool, GetBool);
+ };
+
+ (GetOnly, $name:ident, $level:path, $flag:path, u8) => {
+ sockopt_impl!(GetOnly, $name, $level, $flag, u8, GetU8);
+ };
+
+ (GetOnly, $name:ident, $level:path, $flag:path, usize) => {
+ sockopt_impl!(GetOnly, $name, $level, $flag, usize, GetUsize);
+ };
+
+ (SetOnly, $name:ident, $level:path, $flag:path, bool) => {
+ sockopt_impl!(SetOnly, $name, $level, $flag, bool, SetBool);
+ };
+
+ (SetOnly, $name:ident, $level:path, $flag:path, u8) => {
+ sockopt_impl!(SetOnly, $name, $level, $flag, u8, SetU8);
+ };
+
+ (SetOnly, $name:ident, $level:path, $flag:path, usize) => {
+ sockopt_impl!(SetOnly, $name, $level, $flag, usize, SetUsize);
+ };
+
+ (Both, $name:ident, $level:path, $flag:path, bool) => {
+ sockopt_impl!(Both, $name, $level, $flag, bool, GetBool, SetBool);
+ };
+
+ (Both, $name:ident, $level:path, $flag:path, u8) => {
+ sockopt_impl!(Both, $name, $level, $flag, u8, GetU8, SetU8);
+ };
+
+ (Both, $name:ident, $level:path, $flag:path, usize) => {
+ sockopt_impl!(Both, $name, $level, $flag, usize, GetUsize, SetUsize);
+ };
+
+ (Both, $name:ident, $level:path, $flag:path, OsString<$array:ty>) => {
+ sockopt_impl!(Both, $name, $level, $flag, OsString, GetOsString<$array>, SetOsString);
+ };
+
+ /*
+ * Matchers with generic getter types must be placed at the end, so
+ * they'll only match _after_ specialized matchers fail
+ */
+ (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
+ sockopt_impl!(GetOnly, $name, $level, $flag, $ty, GetStruct<$ty>);
+ };
+
+ (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
+ #[derive(Copy, Clone, Debug)]
+ pub struct $name;
+
+ getsockopt_impl!($name, $level, $flag, $ty, $getter);
+ };
+
+ (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
+ sockopt_impl!(SetOnly, $name, $level, $flag, $ty, SetStruct<$ty>);
+ };
+
+ (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
+ #[derive(Copy, Clone, Debug)]
+ pub struct $name;
+
+ setsockopt_impl!($name, $level, $flag, $ty, $setter);
+ };
+
+ (Both, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty, $setter:ty) => {
+ #[derive(Copy, Clone, Debug)]
+ pub struct $name;
+
+ setsockopt_impl!($name, $level, $flag, $ty, $setter);
+ getsockopt_impl!($name, $level, $flag, $ty, $getter);
+ };
+
+ (Both, $name:ident, $level:path, $flag:path, $ty:ty) => {
+ sockopt_impl!(Both, $name, $level, $flag, $ty, GetStruct<$ty>, SetStruct<$ty>);
+ };
+}
+
+/*
+ *
+ * ===== Define sockopts =====
+ *
+ */
+
+sockopt_impl!(Both, ReuseAddr, libc::SOL_SOCKET, libc::SO_REUSEADDR, bool);
+sockopt_impl!(Both, ReusePort, libc::SOL_SOCKET, libc::SO_REUSEPORT, bool);
+sockopt_impl!(Both, TcpNoDelay, libc::IPPROTO_TCP, libc::TCP_NODELAY, bool);
+sockopt_impl!(Both, Linger, libc::SOL_SOCKET, libc::SO_LINGER, libc::linger);
+sockopt_impl!(SetOnly, IpAddMembership, libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP, super::IpMembershipRequest);
+sockopt_impl!(SetOnly, IpDropMembership, libc::IPPROTO_IP, libc::IP_DROP_MEMBERSHIP, super::IpMembershipRequest);
+cfg_if! {
+ if #[cfg(any(target_os = "android", target_os = "linux"))] {
+ sockopt_impl!(SetOnly, Ipv6AddMembership, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest);
+ sockopt_impl!(SetOnly, Ipv6DropMembership, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest);
+ } else if #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))] {
+ sockopt_impl!(SetOnly, Ipv6AddMembership, libc::IPPROTO_IPV6, libc::IPV6_JOIN_GROUP, super::Ipv6MembershipRequest);
+ sockopt_impl!(SetOnly, Ipv6DropMembership, libc::IPPROTO_IPV6, libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest);
+ }
+}
+sockopt_impl!(Both, IpMulticastTtl, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, u8);
+sockopt_impl!(Both, IpMulticastLoop, libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, bool);
+sockopt_impl!(Both, ReceiveTimeout, libc::SOL_SOCKET, libc::SO_RCVTIMEO, TimeVal);
+sockopt_impl!(Both, SendTimeout, libc::SOL_SOCKET, libc::SO_SNDTIMEO, TimeVal);
+sockopt_impl!(Both, Broadcast, libc::SOL_SOCKET, libc::SO_BROADCAST, bool);
+sockopt_impl!(Both, OobInline, libc::SOL_SOCKET, libc::SO_OOBINLINE, bool);
+sockopt_impl!(GetOnly, SocketError, libc::SOL_SOCKET, libc::SO_ERROR, i32);
+sockopt_impl!(Both, KeepAlive, libc::SOL_SOCKET, libc::SO_KEEPALIVE, bool);
+#[cfg(any(target_os = "android", target_os = "linux"))]
+sockopt_impl!(GetOnly, PeerCredentials, libc::SOL_SOCKET, libc::SO_PEERCRED, super::UnixCredentials);
+#[cfg(any(target_os = "ios",
+ target_os = "macos"))]
+sockopt_impl!(Both, TcpKeepAlive, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, u32);
+#[cfg(any(target_os = "android",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "nacl"))]
+sockopt_impl!(Both, TcpKeepIdle, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32);
+sockopt_impl!(Both, RcvBuf, libc::SOL_SOCKET, libc::SO_RCVBUF, usize);
+sockopt_impl!(Both, SndBuf, libc::SOL_SOCKET, libc::SO_SNDBUF, usize);
+#[cfg(any(target_os = "android", target_os = "linux"))]
+sockopt_impl!(SetOnly, RcvBufForce, libc::SOL_SOCKET, libc::SO_RCVBUFFORCE, usize);
+#[cfg(any(target_os = "android", target_os = "linux"))]
+sockopt_impl!(SetOnly, SndBufForce, libc::SOL_SOCKET, libc::SO_SNDBUFFORCE, usize);
+sockopt_impl!(GetOnly, SockType, libc::SOL_SOCKET, libc::SO_TYPE, super::SockType);
+sockopt_impl!(GetOnly, AcceptConn, libc::SOL_SOCKET, libc::SO_ACCEPTCONN, bool);
+#[cfg(any(target_os = "android", target_os = "linux"))]
+sockopt_impl!(GetOnly, OriginalDst, libc::SOL_IP, libc::SO_ORIGINAL_DST, libc::sockaddr_in);
+sockopt_impl!(Both, ReceiveTimestamp, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool);
+#[cfg(any(target_os = "android", target_os = "linux"))]
+sockopt_impl!(Both, IpTransparent, libc::SOL_IP, libc::IP_TRANSPARENT, bool);
+#[cfg(target_os = "openbsd")]
+sockopt_impl!(Both, BindAny, libc::SOL_SOCKET, libc::SO_BINDANY, bool);
+#[cfg(target_os = "freebsd")]
+sockopt_impl!(Both, BindAny, libc::IPPROTO_IP, libc::IP_BINDANY, bool);
+#[cfg(target_os = "linux")]
+sockopt_impl!(Both, Mark, libc::SOL_SOCKET, libc::SO_MARK, u32);
+#[cfg(any(target_os = "android", target_os = "linux"))]
+sockopt_impl!(Both, PassCred, libc::SOL_SOCKET, libc::SO_PASSCRED, bool);
+#[cfg(any(target_os = "freebsd", target_os = "linux"))]
+sockopt_impl!(Both, TcpCongestion, libc::IPPROTO_TCP, libc::TCP_CONGESTION, OsString<[u8; TCP_CA_NAME_MAX]>);
+#[cfg(any(
+ target_os = "android",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+))]
+sockopt_impl!(Both, Ipv4PacketInfo, libc::IPPROTO_IP, libc::IP_PKTINFO, bool);
+#[cfg(any(
+ target_os = "android",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"
+))]
+sockopt_impl!(Both, Ipv6RecvPacketInfo, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, bool);
+
+
+/*
+ *
+ * ===== Accessor helpers =====
+ *
+ */
+
+/// Helper trait that describes what is expected from a `GetSockOpt` getter.
+unsafe trait Get<T> {
+ /// Returns an empty value.
+ unsafe fn blank() -> Self;
+ /// Returns a pointer to the stored value. This pointer will be passed to the system's
+ /// `getsockopt` call (`man 3p getsockopt`, argument `option_value`).
+ fn ffi_ptr(&mut self) -> *mut c_void;
+ /// Returns length of the stored value. This pointer will be passed to the system's
+ /// `getsockopt` call (`man 3p getsockopt`, argument `option_len`).
+ fn ffi_len(&mut self) -> *mut socklen_t;
+ /// Returns the stored value.
+ unsafe fn unwrap(self) -> T;
+}
+
+/// Helper trait that describes what is expected from a `SetSockOpt` setter.
+unsafe trait Set<'a, T> {
+ /// Initialize the setter with a given value.
+ fn new(val: &'a T) -> Self;
+ /// Returns a pointer to the stored value. This pointer will be passed to the system's
+ /// `setsockopt` call (`man 3p setsockopt`, argument `option_value`).
+ fn ffi_ptr(&self) -> *const c_void;
+ /// Returns length of the stored value. This pointer will be passed to the system's
+ /// `setsockopt` call (`man 3p setsockopt`, argument `option_len`).
+ fn ffi_len(&self) -> socklen_t;
+}
+
+/// Getter for an arbitrary `struct`.
+struct GetStruct<T> {
+ len: socklen_t,
+ val: T,
+}
+
+unsafe impl<T> Get<T> for GetStruct<T> {
+ unsafe fn blank() -> Self {
+ GetStruct {
+ len: mem::size_of::<T>() as socklen_t,
+ val: mem::zeroed(),
+ }
+ }
+
+ fn ffi_ptr(&mut self) -> *mut c_void {
+ &mut self.val as *mut T as *mut c_void
+ }
+
+ fn ffi_len(&mut self) -> *mut socklen_t {
+ &mut self.len
+ }
+
+ unsafe fn unwrap(self) -> T {
+ assert!(self.len as usize == mem::size_of::<T>(), "invalid getsockopt implementation");
+ self.val
+ }
+}
+
+/// Setter for an arbitrary `struct`.
+struct SetStruct<'a, T: 'static> {
+ ptr: &'a T,
+}
+
+unsafe impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
+ fn new(ptr: &'a T) -> SetStruct<'a, T> {
+ SetStruct { ptr: ptr }
+ }
+
+ fn ffi_ptr(&self) -> *const c_void {
+ self.ptr as *const T as *const c_void
+ }
+
+ fn ffi_len(&self) -> socklen_t {
+ mem::size_of::<T>() as socklen_t
+ }
+}
+
+/// Getter for a boolean value.
+struct GetBool {
+ len: socklen_t,
+ val: c_int,
+}
+
+unsafe impl Get<bool> for GetBool {
+ unsafe fn blank() -> Self {
+ GetBool {
+ len: mem::size_of::<c_int>() as socklen_t,
+ val: mem::zeroed(),
+ }
+ }
+
+ fn ffi_ptr(&mut self) -> *mut c_void {
+ &mut self.val as *mut c_int as *mut c_void
+ }
+
+ fn ffi_len(&mut self) -> *mut socklen_t {
+ &mut self.len
+ }
+
+ unsafe fn unwrap(self) -> bool {
+ assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation");
+ self.val != 0
+ }
+}
+
+/// Setter for a boolean value.
+struct SetBool {
+ val: c_int,
+}
+
+unsafe impl<'a> Set<'a, bool> for SetBool {
+ fn new(val: &'a bool) -> SetBool {
+ SetBool { val: if *val { 1 } else { 0 } }
+ }
+
+ fn ffi_ptr(&self) -> *const c_void {
+ &self.val as *const c_int as *const c_void
+ }
+
+ fn ffi_len(&self) -> socklen_t {
+ mem::size_of::<c_int>() as socklen_t
+ }
+}
+
+/// Getter for an `u8` value.
+struct GetU8 {
+ len: socklen_t,
+ val: u8,
+}
+
+unsafe impl Get<u8> for GetU8 {
+ unsafe fn blank() -> Self {
+ GetU8 {
+ len: mem::size_of::<u8>() as socklen_t,
+ val: mem::zeroed(),
+ }
+ }
+
+ fn ffi_ptr(&mut self) -> *mut c_void {
+ &mut self.val as *mut u8 as *mut c_void
+ }
+
+ fn ffi_len(&mut self) -> *mut socklen_t {
+ &mut self.len
+ }
+
+ unsafe fn unwrap(self) -> u8 {
+ assert!(self.len as usize == mem::size_of::<u8>(), "invalid getsockopt implementation");
+ self.val as u8
+ }
+}
+
+/// Setter for an `u8` value.
+struct SetU8 {
+ val: u8,
+}
+
+unsafe impl<'a> Set<'a, u8> for SetU8 {
+ fn new(val: &'a u8) -> SetU8 {
+ SetU8 { val: *val as u8 }
+ }
+
+ fn ffi_ptr(&self) -> *const c_void {
+ &self.val as *const u8 as *const c_void
+ }
+
+ fn ffi_len(&self) -> socklen_t {
+ mem::size_of::<c_int>() as socklen_t
+ }
+}
+
+/// Getter for an `usize` value.
+struct GetUsize {
+ len: socklen_t,
+ val: c_int,
+}
+
+unsafe impl Get<usize> for GetUsize {
+ unsafe fn blank() -> Self {
+ GetUsize {
+ len: mem::size_of::<c_int>() as socklen_t,
+ val: mem::zeroed(),
+ }
+ }
+
+ fn ffi_ptr(&mut self) -> *mut c_void {
+ &mut self.val as *mut c_int as *mut c_void
+ }
+
+ fn ffi_len(&mut self) -> *mut socklen_t {
+ &mut self.len
+ }
+
+ unsafe fn unwrap(self) -> usize {
+ assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation");
+ self.val as usize
+ }
+}
+
+/// Setter for an `usize` value.
+struct SetUsize {
+ val: c_int,
+}
+
+unsafe impl<'a> Set<'a, usize> for SetUsize {
+ fn new(val: &'a usize) -> SetUsize {
+ SetUsize { val: *val as c_int }
+ }
+
+ fn ffi_ptr(&self) -> *const c_void {
+ &self.val as *const c_int as *const c_void
+ }
+
+ fn ffi_len(&self) -> socklen_t {
+ mem::size_of::<c_int>() as socklen_t
+ }
+}
+
+/// Getter for a `OsString` value.
+struct GetOsString<T: AsMut<[u8]>> {
+ len: socklen_t,
+ val: T,
+}
+
+unsafe impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
+ unsafe fn blank() -> Self {
+ GetOsString {
+ len: mem::size_of::<T>() as socklen_t,
+ val: mem::zeroed(),
+ }
+ }
+
+ fn ffi_ptr(&mut self) -> *mut c_void {
+ &mut self.val as *mut T as *mut c_void
+ }
+
+ fn ffi_len(&mut self) -> *mut socklen_t {
+ &mut self.len
+ }
+
+ unsafe fn unwrap(mut self) -> OsString {
+ OsStr::from_bytes(self.val.as_mut()).to_owned()
+ }
+}
+
+/// Setter for a `OsString` value.
+struct SetOsString<'a> {
+ val: &'a OsStr,
+}
+
+unsafe impl<'a> Set<'a, OsString> for SetOsString<'a> {
+ fn new(val: &'a OsString) -> SetOsString {
+ SetOsString { val: val.as_os_str() }
+ }
+
+ fn ffi_ptr(&self) -> *const c_void {
+ self.val.as_bytes().as_ptr() as *const c_void
+ }
+
+ fn ffi_len(&self) -> socklen_t {
+ self.val.len() as socklen_t
+ }
+}
+
+
+#[cfg(test)]
+mod test {
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[test]
+ fn can_get_peercred_on_unix_socket() {
+ use super::super::*;
+
+ let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
+ let a_cred = getsockopt(a, super::PeerCredentials).unwrap();
+ let b_cred = getsockopt(b, super::PeerCredentials).unwrap();
+ assert_eq!(a_cred, b_cred);
+ assert!(a_cred.pid() != 0);
+ }
+
+ #[test]
+ fn is_socket_type_unix() {
+ use super::super::*;
+ use ::unistd::close;
+
+ let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
+ let a_type = getsockopt(a, super::SockType).unwrap();
+ assert!(a_type == SockType::Stream);
+ close(a).unwrap();
+ close(b).unwrap();
+ }
+
+ #[test]
+ fn is_socket_type_dgram() {
+ use super::super::*;
+ use ::unistd::close;
+
+ let s = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap();
+ let s_type = getsockopt(s, super::SockType).unwrap();
+ assert!(s_type == SockType::Datagram);
+ close(s).unwrap();
+ }
+
+ #[cfg(any(target_os = "freebsd",
+ target_os = "linux",
+ target_os = "nacl"))]
+ #[test]
+ fn can_get_listen_on_tcp_socket() {
+ use super::super::*;
+ use ::unistd::close;
+
+ let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
+ let s_listening = getsockopt(s, super::AcceptConn).unwrap();
+ assert!(!s_listening);
+ listen(s, 10).unwrap();
+ let s_listening2 = getsockopt(s, super::AcceptConn).unwrap();
+ assert!(s_listening2);
+ close(s).unwrap();
+ }
+
+ #[cfg(target_os = "linux")]
+ #[test]
+ fn is_so_mark_functional() {
+ use super::super::*;
+ use ::unistd::Uid;
+ use ::std::io::{self, Write};
+
+ if !Uid::current().is_root() {
+ let stderr = io::stderr();
+ let mut handle = stderr.lock();
+ writeln!(handle, "SO_MARK requires root privileges. Skipping test.").unwrap();
+ return;
+ }
+
+ let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
+ setsockopt(s, super::Mark, &1337).unwrap();
+ let mark = getsockopt(s, super::Mark).unwrap();
+ assert_eq!(mark, 1337);
+ }
+}
diff --git a/third_party/rust/nix/src/sys/stat.rs b/third_party/rust/nix/src/sys/stat.rs
new file mode 100644
index 0000000000..1e0936ed86
--- /dev/null
+++ b/third_party/rust/nix/src/sys/stat.rs
@@ -0,0 +1,286 @@
+pub use libc::{dev_t, mode_t};
+pub use libc::stat as FileStat;
+
+use {Result, NixPath};
+use errno::Errno;
+use fcntl::{AtFlags, at_rawfd};
+use libc;
+use std::mem;
+use std::os::unix::io::RawFd;
+use sys::time::{TimeSpec, TimeVal};
+
+libc_bitflags!(
+ pub struct SFlag: mode_t {
+ S_IFIFO;
+ S_IFCHR;
+ S_IFDIR;
+ S_IFBLK;
+ S_IFREG;
+ S_IFLNK;
+ S_IFSOCK;
+ S_IFMT;
+ }
+);
+
+libc_bitflags! {
+ pub struct Mode: mode_t {
+ S_IRWXU;
+ S_IRUSR;
+ S_IWUSR;
+ S_IXUSR;
+ S_IRWXG;
+ S_IRGRP;
+ S_IWGRP;
+ S_IXGRP;
+ S_IRWXO;
+ S_IROTH;
+ S_IWOTH;
+ S_IXOTH;
+ S_ISUID as mode_t;
+ S_ISGID as mode_t;
+ S_ISVTX as mode_t;
+ }
+}
+
+pub fn mknod<P: ?Sized + NixPath>(path: &P, kind: SFlag, perm: Mode, dev: dev_t) -> Result<()> {
+ let res = path.with_nix_path(|cstr| {
+ unsafe {
+ libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev)
+ }
+ })?;
+
+ Errno::result(res).map(drop)
+}
+
+#[cfg(target_os = "linux")]
+pub fn major(dev: dev_t) -> u64 {
+ ((dev >> 32) & 0xffff_f000) |
+ ((dev >> 8) & 0x0000_0fff)
+}
+
+#[cfg(target_os = "linux")]
+pub fn minor(dev: dev_t) -> u64 {
+ ((dev >> 12) & 0xffff_ff00) |
+ ((dev ) & 0x0000_00ff)
+}
+
+#[cfg(target_os = "linux")]
+pub fn makedev(major: u64, minor: u64) -> dev_t {
+ ((major & 0xffff_f000) << 32) |
+ ((major & 0x0000_0fff) << 8) |
+ ((minor & 0xffff_ff00) << 12) |
+ (minor & 0x0000_00ff)
+}
+
+pub fn umask(mode: Mode) -> Mode {
+ let prev = unsafe { libc::umask(mode.bits() as mode_t) };
+ Mode::from_bits(prev).expect("[BUG] umask returned invalid Mode")
+}
+
+pub fn stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
+ let mut dst = unsafe { mem::uninitialized() };
+ let res = path.with_nix_path(|cstr| {
+ unsafe {
+ libc::stat(cstr.as_ptr(), &mut dst as *mut FileStat)
+ }
+ })?;
+
+ Errno::result(res)?;
+
+ Ok(dst)
+}
+
+pub fn lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
+ let mut dst = unsafe { mem::uninitialized() };
+ let res = path.with_nix_path(|cstr| {
+ unsafe {
+ libc::lstat(cstr.as_ptr(), &mut dst as *mut FileStat)
+ }
+ })?;
+
+ Errno::result(res)?;
+
+ Ok(dst)
+}
+
+pub fn fstat(fd: RawFd) -> Result<FileStat> {
+ let mut dst = unsafe { mem::uninitialized() };
+ let res = unsafe { libc::fstat(fd, &mut dst as *mut FileStat) };
+
+ Errno::result(res)?;
+
+ Ok(dst)
+}
+
+pub fn fstatat<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, f: AtFlags) -> Result<FileStat> {
+ let mut dst = unsafe { mem::uninitialized() };
+ let res = pathname.with_nix_path(|cstr| {
+ unsafe { libc::fstatat(dirfd, cstr.as_ptr(), &mut dst as *mut FileStat, f.bits() as libc::c_int) }
+ })?;
+
+ Errno::result(res)?;
+
+ Ok(dst)
+}
+
+/// Change the file permission bits of the file specified by a file descriptor.
+///
+/// # References
+///
+/// [fchmod(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmod.html).
+pub fn fchmod(fd: RawFd, mode: Mode) -> Result<()> {
+ let res = unsafe { libc::fchmod(fd, mode.bits() as mode_t) };
+
+ Errno::result(res).map(drop)
+}
+
+/// Flags for `fchmodat` function.
+#[derive(Clone, Copy, Debug)]
+pub enum FchmodatFlags {
+ FollowSymlink,
+ NoFollowSymlink,
+}
+
+/// Change the file permission bits.
+///
+/// The file to be changed is determined relative to the directory associated
+/// with the file descriptor `dirfd` or the current working directory
+/// if `dirfd` is `None`.
+///
+/// If `flag` is `FchmodatFlags::NoFollowSymlink` and `path` names a symbolic link,
+/// then the mode of the symbolic link is changed.
+///
+/// `fchmod(None, path, mode, FchmodatFlags::FollowSymlink)` is identical to
+/// a call `libc::chmod(path, mode)`. That's why `chmod` is unimplemented
+/// in the `nix` crate.
+///
+/// # References
+///
+/// [fchmodat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html).
+pub fn fchmodat<P: ?Sized + NixPath>(
+ dirfd: Option<RawFd>,
+ path: &P,
+ mode: Mode,
+ flag: FchmodatFlags,
+) -> Result<()> {
+ let atflag =
+ match flag {
+ FchmodatFlags::FollowSymlink => AtFlags::empty(),
+ FchmodatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
+ };
+ let res = path.with_nix_path(|cstr| unsafe {
+ libc::fchmodat(
+ at_rawfd(dirfd),
+ cstr.as_ptr(),
+ mode.bits() as mode_t,
+ atflag.bits() as libc::c_int,
+ )
+ })?;
+
+ Errno::result(res).map(drop)
+}
+
+/// Change the access and modification times of a file.
+///
+/// `utimes(path, times)` is identical to
+/// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)`. The former
+/// is a deprecated API so prefer using the latter if the platforms you care
+/// about support it.
+///
+/// # References
+///
+/// [utimes(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/utimes.html).
+pub fn utimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> {
+ let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
+ let res = path.with_nix_path(|cstr| unsafe {
+ libc::utimes(cstr.as_ptr(), &times[0])
+ })?;
+
+ Errno::result(res).map(drop)
+}
+
+/// Change the access and modification times of a file without following symlinks.
+///
+/// `lutimes(path, times)` is identical to
+/// `utimensat(None, path, times, UtimensatFlags::NoFollowSymlink)`. The former
+/// is a deprecated API so prefer using the latter if the platforms you care
+/// about support it.
+///
+/// # References
+///
+/// [lutimes(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lutimes.html).
+#[cfg(any(target_os = "linux",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "freebsd",
+ target_os = "netbsd"))]
+pub fn lutimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> {
+ let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
+ let res = path.with_nix_path(|cstr| unsafe {
+ libc::lutimes(cstr.as_ptr(), &times[0])
+ })?;
+
+ Errno::result(res).map(drop)
+}
+
+/// Change the access and modification times of the file specified by a file descriptor.
+///
+/// # References
+///
+/// [futimens(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html).
+#[inline]
+pub fn futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()> {
+ let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
+ let res = unsafe { libc::futimens(fd, &times[0]) };
+
+ Errno::result(res).map(drop)
+}
+
+/// Flags for `utimensat` function.
+#[derive(Clone, Copy, Debug)]
+pub enum UtimensatFlags {
+ FollowSymlink,
+ NoFollowSymlink,
+}
+
+/// Change the access and modification times of a file.
+///
+/// The file to be changed is determined relative to the directory associated
+/// with the file descriptor `dirfd` or the current working directory
+/// if `dirfd` is `None`.
+///
+/// If `flag` is `UtimensatFlags::NoFollowSymlink` and `path` names a symbolic link,
+/// then the mode of the symbolic link is changed.
+///
+/// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)` is identical to
+/// `utimes(path, times)`. The latter is a deprecated API so prefer using the
+/// former if the platforms you care about support it.
+///
+/// # References
+///
+/// [utimensat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html).
+pub fn utimensat<P: ?Sized + NixPath>(
+ dirfd: Option<RawFd>,
+ path: &P,
+ atime: &TimeSpec,
+ mtime: &TimeSpec,
+ flag: UtimensatFlags
+) -> Result<()> {
+ let atflag =
+ match flag {
+ UtimensatFlags::FollowSymlink => AtFlags::empty(),
+ UtimensatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
+ };
+ let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
+ let res = path.with_nix_path(|cstr| unsafe {
+ libc::utimensat(
+ at_rawfd(dirfd),
+ cstr.as_ptr(),
+ &times[0],
+ atflag.bits() as libc::c_int,
+ )
+ })?;
+
+ Errno::result(res).map(drop)
+}
diff --git a/third_party/rust/nix/src/sys/statfs.rs b/third_party/rust/nix/src/sys/statfs.rs
new file mode 100644
index 0000000000..e7ffae5e4e
--- /dev/null
+++ b/third_party/rust/nix/src/sys/statfs.rs
@@ -0,0 +1,20 @@
+use {Result, NixPath};
+use errno::Errno;
+use std::os::unix::io::AsRawFd;
+use libc;
+
+pub fn statfs<P: ?Sized + NixPath>(path: &P, stat: &mut libc::statfs) -> Result<()> {
+ unsafe {
+ Errno::clear();
+ let res = path.with_nix_path(|path| libc::statfs(path.as_ptr(), stat))?;
+
+ Errno::result(res).map(drop)
+ }
+}
+
+pub fn fstatfs<T: AsRawFd>(fd: &T, stat: &mut libc::statfs) -> Result<()> {
+ unsafe {
+ Errno::clear();
+ Errno::result(libc::fstatfs(fd.as_raw_fd(), stat)).map(drop)
+ }
+}
diff --git a/third_party/rust/nix/src/sys/statvfs.rs b/third_party/rust/nix/src/sys/statvfs.rs
new file mode 100644
index 0000000000..de69ae51f8
--- /dev/null
+++ b/third_party/rust/nix/src/sys/statvfs.rs
@@ -0,0 +1,161 @@
+//! Get filesystem statistics
+//!
+//! See [the man pages](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatvfs.html)
+//! for more details.
+use std::mem;
+use std::os::unix::io::AsRawFd;
+
+use libc::{self, c_ulong};
+
+use {Result, NixPath};
+use errno::Errno;
+
+libc_bitflags!(
+ /// File system mount Flags
+ #[repr(C)]
+ #[derive(Default)]
+ pub struct FsFlags: c_ulong {
+ /// Read Only
+ ST_RDONLY;
+ /// Do not allow the set-uid bits to have an effect
+ ST_NOSUID;
+ /// Do not interpret character or block-special devices
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ ST_NODEV;
+ /// Do not allow execution of binaries on the filesystem
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ ST_NOEXEC;
+ /// All IO should be done synchronously
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ ST_SYNCHRONOUS;
+ /// Allow mandatory locks on the filesystem
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ ST_MANDLOCK;
+ /// Write on file/directory/symlink
+ #[cfg(target_os = "linux")]
+ ST_WRITE;
+ /// Append-only file
+ #[cfg(target_os = "linux")]
+ ST_APPEND;
+ /// Immutable file
+ #[cfg(target_os = "linux")]
+ ST_IMMUTABLE;
+ /// Do not update access times on files
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ ST_NOATIME;
+ /// Do not update access times on files
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ ST_NODIRATIME;
+ /// Update access time relative to modify/change time
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_env = "musl"))))]
+ ST_RELATIME;
+ }
+);
+
+/// Wrapper around the POSIX `statvfs` struct
+///
+/// For more information see the [`statvfs(3)` man pages](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_statvfs.h.html).
+// FIXME: Replace with repr(transparent)
+#[repr(C)]
+#[derive(Clone, Copy)]
+#[allow(missing_debug_implementations)]
+pub struct Statvfs(libc::statvfs);
+
+impl Statvfs {
+ /// get the file system block size
+ pub fn block_size(&self) -> c_ulong {
+ self.0.f_bsize
+ }
+
+ /// Get the fundamental file system block size
+ pub fn fragment_size(&self) -> c_ulong {
+ self.0.f_frsize
+ }
+
+ /// Get the number of blocks.
+ ///
+ /// Units are in units of `fragment_size()`
+ pub fn blocks(&self) -> libc::fsblkcnt_t {
+ self.0.f_blocks
+ }
+
+ /// Get the number of free blocks in the file system
+ pub fn blocks_free(&self) -> libc::fsblkcnt_t {
+ self.0.f_bfree
+ }
+
+ /// Get the number of free blocks for unprivileged users
+ pub fn blocks_available(&self) -> libc::fsblkcnt_t {
+ self.0.f_bavail
+ }
+
+ /// Get the total number of file inodes
+ pub fn files(&self) -> libc::fsfilcnt_t {
+ self.0.f_files
+ }
+
+ /// Get the number of free file inodes
+ pub fn files_free(&self) -> libc::fsfilcnt_t {
+ self.0.f_ffree
+ }
+
+ /// Get the number of free file inodes for unprivileged users
+ pub fn files_available(&self) -> libc::fsfilcnt_t {
+ self.0.f_favail
+ }
+
+ /// Get the file system id
+ pub fn filesystem_id(&self) -> c_ulong {
+ self.0.f_fsid
+ }
+
+ /// Get the mount flags
+ pub fn flags(&self) -> FsFlags {
+ FsFlags::from_bits_truncate(self.0.f_flag)
+ }
+
+ /// Get the maximum filename length
+ pub fn name_max(&self) -> c_ulong {
+ self.0.f_namemax
+ }
+
+}
+
+/// Return a `Statvfs` object with information about the `path`
+pub fn statvfs<P: ?Sized + NixPath>(path: &P) -> Result<Statvfs> {
+ unsafe {
+ Errno::clear();
+ let mut stat: Statvfs = mem::uninitialized();
+ let res = path.with_nix_path(|path|
+ libc::statvfs(path.as_ptr(), &mut stat.0)
+ )?;
+
+ Errno::result(res).map(|_| stat)
+ }
+}
+
+/// Return a `Statvfs` object with information about `fd`
+pub fn fstatvfs<T: AsRawFd>(fd: &T) -> Result<Statvfs> {
+ unsafe {
+ Errno::clear();
+ let mut stat: Statvfs = mem::uninitialized();
+ Errno::result(libc::fstatvfs(fd.as_raw_fd(), &mut stat.0)).map(|_| stat)
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use std::fs::File;
+ use sys::statvfs::*;
+
+ #[test]
+ fn statvfs_call() {
+ statvfs("/".as_bytes()).unwrap();
+ }
+
+ #[test]
+ fn fstatvfs_call() {
+ let root = File::open("/").unwrap();
+ fstatvfs(&root).unwrap();
+ }
+}
diff --git a/third_party/rust/nix/src/sys/sysinfo.rs b/third_party/rust/nix/src/sys/sysinfo.rs
new file mode 100644
index 0000000000..98ef7bd517
--- /dev/null
+++ b/third_party/rust/nix/src/sys/sysinfo.rs
@@ -0,0 +1,73 @@
+use libc::{self, SI_LOAD_SHIFT};
+use std::{cmp, mem};
+use std::time::Duration;
+
+use Result;
+use errno::Errno;
+
+/// System info structure returned by `sysinfo`.
+#[derive(Copy, Clone)]
+#[allow(missing_debug_implementations)] // libc::sysinfo doesn't impl Debug
+pub struct SysInfo(libc::sysinfo);
+
+impl SysInfo {
+ /// Returns the load average tuple.
+ ///
+ /// The returned values represent the load average over time intervals of
+ /// 1, 5, and 15 minutes, respectively.
+ pub fn load_average(&self) -> (f64, f64, f64) {
+ (
+ self.0.loads[0] as f64 / (1 << SI_LOAD_SHIFT) as f64,
+ self.0.loads[1] as f64 / (1 << SI_LOAD_SHIFT) as f64,
+ self.0.loads[2] as f64 / (1 << SI_LOAD_SHIFT) as f64,
+ )
+ }
+
+ /// Returns the time since system boot.
+ pub fn uptime(&self) -> Duration {
+ // Truncate negative values to 0
+ Duration::from_secs(cmp::max(self.0.uptime, 0) as u64)
+ }
+
+ /// Current number of processes.
+ pub fn process_count(&self) -> u16 {
+ self.0.procs
+ }
+
+ /// Returns the amount of swap memory in Bytes.
+ pub fn swap_total(&self) -> u64 {
+ self.scale_mem(self.0.totalswap)
+ }
+
+ /// Returns the amount of unused swap memory in Bytes.
+ pub fn swap_free(&self) -> u64 {
+ self.scale_mem(self.0.freeswap)
+ }
+
+ /// Returns the total amount of installed RAM in Bytes.
+ pub fn ram_total(&self) -> u64 {
+ self.scale_mem(self.0.totalram)
+ }
+
+ /// Returns the amount of completely unused RAM in Bytes.
+ ///
+ /// "Unused" in this context means that the RAM in neither actively used by
+ /// programs, nor by the operating system as disk cache or buffer. It is
+ /// "wasted" RAM since it currently serves no purpose.
+ pub fn ram_unused(&self) -> u64 {
+ self.scale_mem(self.0.freeram)
+ }
+
+ fn scale_mem(&self, units: libc::c_ulong) -> u64 {
+ units as u64 * self.0.mem_unit as u64
+ }
+}
+
+/// Returns system information.
+///
+/// [See `sysinfo(2)`](http://man7.org/linux/man-pages/man2/sysinfo.2.html).
+pub fn sysinfo() -> Result<SysInfo> {
+ let mut info: libc::sysinfo = unsafe { mem::uninitialized() };
+ let res = unsafe { libc::sysinfo(&mut info) };
+ Errno::result(res).map(|_| SysInfo(info))
+}
diff --git a/third_party/rust/nix/src/sys/termios.rs b/third_party/rust/nix/src/sys/termios.rs
new file mode 100644
index 0000000000..d8815baa00
--- /dev/null
+++ b/third_party/rust/nix/src/sys/termios.rs
@@ -0,0 +1,1108 @@
+//! An interface for controlling asynchronous communication ports
+//!
+//! This interface provides a safe wrapper around the termios subsystem defined by POSIX. The
+//! underlying types are all implemented in libc for most platforms and either wrapped in safer
+//! types here or exported directly.
+//!
+//! If you are unfamiliar with the `termios` API, you should first read the
+//! [API documentation](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/termios.h.html) and
+//! then come back to understand how `nix` safely wraps it.
+//!
+//! It should be noted that this API incurs some runtime overhead above the base `libc` definitions.
+//! As this interface is not used with high-bandwidth information, this should be fine in most
+//! cases. The primary cost when using this API is that the `Termios` datatype here duplicates the
+//! standard fields of the underlying `termios` struct and uses safe type wrappers for those fields.
+//! This means that when crossing the FFI interface to the underlying C library, data is first
+//! copied into the underlying `termios` struct, then the operation is done, and the data is copied
+//! back (with additional sanity checking) into the safe wrapper types. The `termios` struct is
+//! relatively small across all platforms (on the order of 32-64 bytes).
+//!
+//! The following examples highlight some of the API use cases such that users coming from using C
+//! or reading the standard documentation will understand how to use the safe API exposed here.
+//!
+//! Example disabling processing of the end-of-file control character:
+//!
+//! ```
+//! # use self::nix::sys::termios::SpecialCharacterIndices::VEOF;
+//! # use self::nix::sys::termios::{_POSIX_VDISABLE, Termios};
+//! # let mut termios = unsafe { Termios::default_uninit() };
+//! termios.control_chars[VEOF as usize] = _POSIX_VDISABLE;
+//! ```
+//!
+//! The flags within `Termios` are defined as bitfields using the `bitflags` crate. This provides
+//! an interface for working with bitfields that is similar to working with the raw unsigned
+//! integer types but offers type safety because of the internal checking that values will always
+//! be a valid combination of the defined flags.
+//!
+//! An example showing some of the basic operations for interacting with the control flags:
+//!
+//! ```
+//! # use self::nix::sys::termios::{ControlFlags, Termios};
+//! # let mut termios = unsafe { Termios::default_uninit() };
+//! termios.control_flags & ControlFlags::CSIZE == ControlFlags::CS5;
+//! termios.control_flags |= ControlFlags::CS5;
+//! ```
+//!
+//! # Baud rates
+//!
+//! This API is not consistent across platforms when it comes to `BaudRate`: Android and Linux both
+//! only support the rates specified by the `BaudRate` enum through their termios API while the BSDs
+//! support arbitrary baud rates as the values of the `BaudRate` enum constants are the same integer
+//! value of the constant (`B9600` == `9600`). Therefore the `nix::termios` API uses the following
+//! conventions:
+//!
+//! * `cfgetispeed()` - Returns `u32` on BSDs, `BaudRate` on Android/Linux
+//! * `cfgetospeed()` - Returns `u32` on BSDs, `BaudRate` on Android/Linux
+//! * `cfsetispeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux
+//! * `cfsetospeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux
+//! * `cfsetspeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux
+//!
+//! The most common use case of specifying a baud rate using the enum will work the same across
+//! platforms:
+//!
+//! ```rust
+//! # #[macro_use] extern crate nix;
+//! # use nix::sys::termios::{BaudRate, cfsetispeed, cfsetospeed, cfsetspeed, Termios};
+//! # fn main() {
+//! # let mut t = unsafe { Termios::default_uninit() };
+//! cfsetispeed(&mut t, BaudRate::B9600);
+//! cfsetospeed(&mut t, BaudRate::B9600);
+//! cfsetspeed(&mut t, BaudRate::B9600);
+//! # }
+//! ```
+//!
+//! Additionally round-tripping baud rates is consistent across platforms:
+//!
+//! ```rust
+//! # extern crate nix;
+//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetispeed, cfsetspeed, Termios};
+//! # fn main() {
+//! # let mut t = unsafe { Termios::default_uninit() };
+//! # cfsetspeed(&mut t, BaudRate::B9600);
+//! let speed = cfgetispeed(&t);
+//! assert!(speed == cfgetospeed(&t));
+//! cfsetispeed(&mut t, speed);
+//! # }
+//! ```
+//!
+//! On non-BSDs, `cfgetispeed()` and `cfgetospeed()` both return a `BaudRate`:
+//!
+// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version
+#![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+ target_os = "macos", target_os = "netbsd", target_os = "openbsd"),
+ doc = " ```rust,ignore")]
+#![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+ target_os = "macos", target_os = "netbsd", target_os = "openbsd")),
+ doc = " ```rust")]
+//! # extern crate nix;
+//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios};
+//! # fn main() {
+//! # let mut t = unsafe { Termios::default_uninit() };
+//! # cfsetspeed(&mut t, BaudRate::B9600);
+//! assert!(cfgetispeed(&t) == BaudRate::B9600);
+//! assert!(cfgetospeed(&t) == BaudRate::B9600);
+//! # }
+//! ```
+//!
+//! But on the BSDs, `cfgetispeed()` and `cfgetospeed()` both return `u32`s:
+//!
+// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version
+#![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+ target_os = "macos", target_os = "netbsd", target_os = "openbsd"),
+ doc = " ```rust")]
+#![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+ target_os = "macos", target_os = "netbsd", target_os = "openbsd")),
+ doc = " ```rust,ignore")]
+//! # extern crate nix;
+//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios};
+//! # fn main() {
+//! # let mut t = unsafe { Termios::default_uninit() };
+//! # cfsetspeed(&mut t, 9600u32);
+//! assert!(cfgetispeed(&t) == 9600u32);
+//! assert!(cfgetospeed(&t) == 9600u32);
+//! # }
+//! ```
+//!
+//! It's trivial to convert from a `BaudRate` to a `u32` on BSDs:
+//!
+// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version
+#![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+ target_os = "macos", target_os = "netbsd", target_os = "openbsd"),
+ doc = " ```rust")]
+#![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+ target_os = "macos", target_os = "netbsd", target_os = "openbsd")),
+ doc = " ```rust,ignore")]
+//! # extern crate nix;
+//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfsetspeed, Termios};
+//! # fn main() {
+//! # let mut t = unsafe { Termios::default_uninit() };
+//! # cfsetspeed(&mut t, 9600u32);
+//! assert!(cfgetispeed(&t) == BaudRate::B9600.into());
+//! assert!(u32::from(BaudRate::B9600) == 9600u32);
+//! # }
+//! ```
+//!
+//! And on BSDs you can specify arbitrary baud rates (**note** this depends on hardware support)
+//! by specifying baud rates directly using `u32`s:
+//!
+// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version
+#![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+ target_os = "macos", target_os = "netbsd", target_os = "openbsd"),
+ doc = " ```rust")]
+#![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+ target_os = "macos", target_os = "netbsd", target_os = "openbsd")),
+ doc = " ```rust,ignore")]
+//! # extern crate nix;
+//! # use nix::sys::termios::{cfsetispeed, cfsetospeed, cfsetspeed, Termios};
+//! # fn main() {
+//! # let mut t = unsafe { Termios::default_uninit() };
+//! cfsetispeed(&mut t, 9600u32);
+//! cfsetospeed(&mut t, 9600u32);
+//! cfsetspeed(&mut t, 9600u32);
+//! # }
+//! ```
+use Result;
+use errno::Errno;
+use libc::{self, c_int, tcflag_t};
+use std::cell::{Ref, RefCell};
+use std::convert::From;
+use std::mem;
+use std::os::unix::io::RawFd;
+
+use ::unistd::Pid;
+
+/// Stores settings for the termios API
+///
+/// This is a wrapper around the `libc::termios` struct that provides a safe interface for the
+/// standard fields. The only safe way to obtain an instance of this struct is to extract it from
+/// an open port using `tcgetattr()`.
+#[derive(Clone)]
+#[allow(missing_debug_implementations)]
+pub struct Termios {
+ inner: RefCell<libc::termios>,
+ /// Input mode flags (see `termios.c_iflag` documentation)
+ pub input_flags: InputFlags,
+ /// Output mode flags (see `termios.c_oflag` documentation)
+ pub output_flags: OutputFlags,
+ /// Control mode flags (see `termios.c_cflag` documentation)
+ pub control_flags: ControlFlags,
+ /// Local mode flags (see `termios.c_lflag` documentation)
+ pub local_flags: LocalFlags,
+ /// Control characters (see `termios.c_cc` documentation)
+ pub control_chars: [libc::cc_t; NCCS],
+}
+
+impl Termios {
+ /// Exposes an immutable reference to the underlying `libc::termios` data structure.
+ ///
+ /// This can be used for interfacing with other FFI functions like:
+ ///
+ /// ```rust
+ /// # extern crate libc;
+ /// # extern crate nix;
+ /// # fn main() {
+ /// # use nix::sys::termios::Termios;
+ /// # let mut termios = unsafe { Termios::default_uninit() };
+ /// let inner_termios = termios.get_libc_termios();
+ /// unsafe { libc::cfgetispeed(&*inner_termios) };
+ /// # }
+ /// ```
+ ///
+ /// There is no public API exposed for functions that modify the underlying `libc::termios`
+ /// data because it requires additional work to maintain type safety.
+ // FIXME: Switch this over to use pub(crate)
+ #[doc(hidden)]
+ pub fn get_libc_termios(&self) -> Ref<libc::termios> {
+ {
+ let mut termios = self.inner.borrow_mut();
+ termios.c_iflag = self.input_flags.bits();
+ termios.c_oflag = self.output_flags.bits();
+ termios.c_cflag = self.control_flags.bits();
+ termios.c_lflag = self.local_flags.bits();
+ termios.c_cc = self.control_chars;
+ }
+ self.inner.borrow()
+ }
+
+ /// Exposes the inner `libc::termios` datastore within `Termios`.
+ ///
+ /// This is unsafe because if this is used to modify the inner libc::termios struct, it will not
+ /// automatically update the safe wrapper type around it. Therefore we disable docs to
+ /// effectively limit its use to nix internals. In this case it should also be paired with a
+ /// call to `update_wrapper()` so that the wrapper-type and internal representation stay
+ /// consistent.
+ unsafe fn get_libc_termios_mut(&mut self) -> *mut libc::termios {
+ {
+ let mut termios = self.inner.borrow_mut();
+ termios.c_iflag = self.input_flags.bits();
+ termios.c_oflag = self.output_flags.bits();
+ termios.c_cflag = self.control_flags.bits();
+ termios.c_lflag = self.local_flags.bits();
+ termios.c_cc = self.control_chars;
+ }
+ self.inner.as_ptr()
+ }
+
+ /// Allows for easily creating new `Termios` structs that will be overwritten with real data.
+ ///
+ /// This should only be used when the inner libc::termios struct will be overwritten before it's
+ /// read.
+ // FIXME: Switch this over to use pub(crate)
+ #[doc(hidden)]
+ pub unsafe fn default_uninit() -> Self {
+ Termios {
+ inner: RefCell::new(mem::uninitialized()),
+ input_flags: InputFlags::empty(),
+ output_flags: OutputFlags::empty(),
+ control_flags: ControlFlags::empty(),
+ local_flags: LocalFlags::empty(),
+ control_chars: [0 as libc::cc_t; NCCS],
+ }
+ }
+
+ /// Updates the wrapper values from the internal `libc::termios` data structure.
+ #[doc(hidden)]
+ pub fn update_wrapper(&mut self) {
+ let termios = *self.inner.borrow_mut();
+ self.input_flags = InputFlags::from_bits_truncate(termios.c_iflag);
+ self.output_flags = OutputFlags::from_bits_truncate(termios.c_oflag);
+ self.control_flags = ControlFlags::from_bits_truncate(termios.c_cflag);
+ self.local_flags = LocalFlags::from_bits_truncate(termios.c_lflag);
+ self.control_chars = termios.c_cc;
+ }
+}
+
+impl From<libc::termios> for Termios {
+ fn from(termios: libc::termios) -> Self {
+ Termios {
+ inner: RefCell::new(termios),
+ input_flags: InputFlags::from_bits_truncate(termios.c_iflag),
+ output_flags: OutputFlags::from_bits_truncate(termios.c_oflag),
+ control_flags: ControlFlags::from_bits_truncate(termios.c_cflag),
+ local_flags: LocalFlags::from_bits_truncate(termios.c_lflag),
+ control_chars: termios.c_cc,
+ }
+ }
+}
+
+impl From<Termios> for libc::termios {
+ fn from(termios: Termios) -> Self {
+ termios.inner.into_inner()
+ }
+}
+
+libc_enum!{
+ /// Baud rates supported by the system.
+ ///
+ /// For the BSDs, arbitrary baud rates can be specified by using `u32`s directly instead of this
+ /// enum.
+ ///
+ /// B0 is special and will disable the port.
+ #[cfg_attr(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64"), repr(u64))]
+ #[cfg_attr(not(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64")), repr(u32))]
+ pub enum BaudRate {
+ B0,
+ B50,
+ B75,
+ B110,
+ B134,
+ B150,
+ B200,
+ B300,
+ B600,
+ B1200,
+ B1800,
+ B2400,
+ B4800,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ B7200,
+ B9600,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ B14400,
+ B19200,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ B28800,
+ B38400,
+ B57600,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ B76800,
+ B115200,
+ B230400,
+ #[cfg(any(target_os = "android",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "netbsd"))]
+ B460800,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ B500000,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ B576000,
+ #[cfg(any(target_os = "android",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "netbsd"))]
+ B921600,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ B1000000,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ B1152000,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ B1500000,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ B2000000,
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
+ B2500000,
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
+ B3000000,
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
+ B3500000,
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
+ B4000000,
+ }
+}
+
+impl From<libc::speed_t> for BaudRate {
+ fn from(s: libc::speed_t) -> BaudRate {
+
+ use libc::{B0, B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400, B4800,
+ B9600, B19200, B38400, B57600, B115200, B230400};
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ use libc::{B500000, B576000, B1000000, B1152000, B1500000, B2000000};
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
+ use libc::{B2500000, B3000000, B3500000, B4000000};
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ use libc::{B7200, B14400, B28800, B76800};
+ #[cfg(any(target_os = "android",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "netbsd"))]
+ use libc::{B460800, B921600};
+
+ match s {
+ B0 => BaudRate::B0,
+ B50 => BaudRate::B50,
+ B75 => BaudRate::B75,
+ B110 => BaudRate::B110,
+ B134 => BaudRate::B134,
+ B150 => BaudRate::B150,
+ B200 => BaudRate::B200,
+ B300 => BaudRate::B300,
+ B600 => BaudRate::B600,
+ B1200 => BaudRate::B1200,
+ B1800 => BaudRate::B1800,
+ B2400 => BaudRate::B2400,
+ B4800 => BaudRate::B4800,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ B7200 => BaudRate::B7200,
+ B9600 => BaudRate::B9600,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ B14400 => BaudRate::B14400,
+ B19200 => BaudRate::B19200,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ B28800 => BaudRate::B28800,
+ B38400 => BaudRate::B38400,
+ B57600 => BaudRate::B57600,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ B76800 => BaudRate::B76800,
+ B115200 => BaudRate::B115200,
+ B230400 => BaudRate::B230400,
+ #[cfg(any(target_os = "android",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "netbsd"))]
+ B460800 => BaudRate::B460800,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ B500000 => BaudRate::B500000,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ B576000 => BaudRate::B576000,
+ #[cfg(any(target_os = "android",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "netbsd"))]
+ B921600 => BaudRate::B921600,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ B1000000 => BaudRate::B1000000,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ B1152000 => BaudRate::B1152000,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ B1500000 => BaudRate::B1500000,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ B2000000 => BaudRate::B2000000,
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
+ B2500000 => BaudRate::B2500000,
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
+ B3000000 => BaudRate::B3000000,
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
+ B3500000 => BaudRate::B3500000,
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
+ B4000000 => BaudRate::B4000000,
+ b => unreachable!("Invalid baud constant: {}", b),
+ }
+ }
+}
+
+// TODO: Include `TryFrom<u32> for BaudRate` once that API stabilizes
+#[cfg(any(target_os = "freebsd",
+ target_os = "dragonfly",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+impl From<BaudRate> for u32 {
+ fn from(b: BaudRate) -> u32 {
+ b as u32
+ }
+}
+
+// TODO: Add TCSASOFT, which will require treating this as a bitfield.
+libc_enum! {
+ /// Specify when a port configuration change should occur.
+ ///
+ /// Used as an argument to `tcsetattr()`
+ #[repr(i32)]
+ pub enum SetArg {
+ /// The change will occur immediately
+ TCSANOW,
+ /// The change occurs after all output has been written
+ TCSADRAIN,
+ /// Same as `TCSADRAIN`, but will also flush the input buffer
+ TCSAFLUSH,
+ }
+}
+
+libc_enum! {
+ /// Specify a combination of the input and output buffers to flush
+ ///
+ /// Used as an argument to `tcflush()`.
+ #[repr(i32)]
+ pub enum FlushArg {
+ /// Flush data that was received but not read
+ TCIFLUSH,
+ /// Flush data written but not transmitted
+ TCOFLUSH,
+ /// Flush both received data not read and written data not transmitted
+ TCIOFLUSH,
+ }
+}
+
+libc_enum! {
+ /// Specify how transmission flow should be altered
+ ///
+ /// Used as an argument to `tcflow()`.
+ #[repr(i32)]
+ pub enum FlowArg {
+ /// Suspend transmission
+ TCOOFF,
+ /// Resume transmission
+ TCOON,
+ /// Transmit a STOP character, which should disable a connected terminal device
+ TCIOFF,
+ /// Transmit a START character, which should re-enable a connected terminal device
+ TCION,
+ }
+}
+
+// TODO: Make this usable directly as a slice index.
+libc_enum! {
+ /// Indices into the `termios.c_cc` array for special characters.
+ #[repr(usize)]
+ pub enum SpecialCharacterIndices {
+ VDISCARD,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ VDSUSP,
+ VEOF,
+ VEOL,
+ VEOL2,
+ VERASE,
+ #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
+ VERASE2,
+ VINTR,
+ VKILL,
+ VLNEXT,
+ #[cfg(not(all(target_os = "linux", target_arch = "sparc64")))]
+ VMIN,
+ VQUIT,
+ VREPRINT,
+ VSTART,
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ VSTATUS,
+ VSTOP,
+ VSUSP,
+ #[cfg(target_os = "linux")]
+ VSWTC,
+ #[cfg(target_os = "haiku")]
+ VSWTCH,
+ #[cfg(not(all(target_os = "linux", target_arch = "sparc64")))]
+ VTIME,
+ VWERASE,
+ #[cfg(target_os = "dragonfly")]
+ VCHECKPT,
+ }
+}
+
+pub use libc::NCCS;
+#[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+pub use libc::_POSIX_VDISABLE;
+
+libc_bitflags! {
+ /// Flags for configuring the input mode of a terminal
+ pub struct InputFlags: tcflag_t {
+ IGNBRK;
+ BRKINT;
+ IGNPAR;
+ PARMRK;
+ INPCK;
+ ISTRIP;
+ INLCR;
+ IGNCR;
+ ICRNL;
+ IXON;
+ IXOFF;
+ IXANY;
+ IMAXBEL;
+ #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
+ IUTF8;
+ }
+}
+
+libc_bitflags! {
+ /// Flags for configuring the output mode of a terminal
+ pub struct OutputFlags: tcflag_t {
+ OPOST;
+ #[cfg(any(target_os = "android",
+ target_os = "haiku",
+ target_os = "linux",
+ target_os = "openbsd"))]
+ OLCUC;
+ ONLCR;
+ OCRNL as tcflag_t;
+ ONOCR as tcflag_t;
+ ONLRET as tcflag_t;
+ #[cfg(any(target_os = "android",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ OFILL as tcflag_t;
+ #[cfg(any(target_os = "android",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ OFDEL as tcflag_t;
+ #[cfg(any(target_os = "android",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ NL0 as tcflag_t;
+ #[cfg(any(target_os = "android",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ NL1 as tcflag_t;
+ #[cfg(any(target_os = "android",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ CR0 as tcflag_t;
+ #[cfg(any(target_os = "android",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ CR1 as tcflag_t;
+ #[cfg(any(target_os = "android",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ CR2 as tcflag_t;
+ #[cfg(any(target_os = "android",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ CR3 as tcflag_t;
+ #[cfg(any(target_os = "android",
+ target_os = "freebsd",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ TAB0 as tcflag_t;
+ #[cfg(any(target_os = "android",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ TAB1 as tcflag_t;
+ #[cfg(any(target_os = "android",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ TAB2 as tcflag_t;
+ #[cfg(any(target_os = "android",
+ target_os = "freebsd",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ TAB3 as tcflag_t;
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ XTABS;
+ #[cfg(any(target_os = "android",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ BS0 as tcflag_t;
+ #[cfg(any(target_os = "android",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ BS1 as tcflag_t;
+ #[cfg(any(target_os = "android",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ VT0 as tcflag_t;
+ #[cfg(any(target_os = "android",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ VT1 as tcflag_t;
+ #[cfg(any(target_os = "android",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ FF0 as tcflag_t;
+ #[cfg(any(target_os = "android",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ FF1 as tcflag_t;
+ #[cfg(any(target_os = "freebsd",
+ target_os = "dragonfly",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ OXTABS;
+ #[cfg(any(target_os = "freebsd",
+ target_os = "dragonfly",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ ONOEOT as tcflag_t;
+
+ // Bitmasks for use with OutputFlags to select specific settings
+ // These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110
+ // is resolved.
+
+ #[cfg(any(target_os = "android",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ NLDLY as tcflag_t; // FIXME: Datatype needs to be corrected in libc for mac
+ #[cfg(any(target_os = "android",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ CRDLY as tcflag_t;
+ #[cfg(any(target_os = "android",
+ target_os = "freebsd",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ TABDLY as tcflag_t;
+ #[cfg(any(target_os = "android",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ BSDLY as tcflag_t;
+ #[cfg(any(target_os = "android",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ VTDLY as tcflag_t;
+ #[cfg(any(target_os = "android",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos"))]
+ FFDLY as tcflag_t;
+ }
+}
+
+libc_bitflags! {
+ /// Flags for setting the control mode of a terminal
+ pub struct ControlFlags: tcflag_t {
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ CIGNORE;
+ CS5;
+ CS6;
+ CS7;
+ CS8;
+ CSTOPB;
+ CREAD;
+ PARENB;
+ PARODD;
+ HUPCL;
+ CLOCAL;
+ CRTSCTS;
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ CBAUD;
+ #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "mips"))))]
+ CMSPAR;
+ #[cfg(any(target_os = "android",
+ all(target_os = "linux",
+ not(any(target_arch = "powerpc", target_arch = "powerpc64")))))]
+ CIBAUD;
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ CBAUDEX;
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ MDMBUF;
+ #[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
+ CHWFLOW;
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ CCTS_OFLOW;
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ CRTS_IFLOW;
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd"))]
+ CDTR_IFLOW;
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd"))]
+ CDSR_OFLOW;
+ #[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd"))]
+ CCAR_OFLOW;
+
+ // Bitmasks for use with ControlFlags to select specific settings
+ // These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110
+ // is resolved.
+
+ CSIZE;
+ }
+}
+
+libc_bitflags! {
+ /// Flags for setting any local modes
+ pub struct LocalFlags: tcflag_t {
+ ECHOKE;
+ ECHOE;
+ ECHOK;
+ ECHO;
+ ECHONL;
+ ECHOPRT;
+ ECHOCTL;
+ ISIG;
+ ICANON;
+ #[cfg(any(target_os = "freebsd",
+ target_os = "dragonfly",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ ALTWERASE;
+ IEXTEN;
+ EXTPROC;
+ TOSTOP;
+ FLUSHO;
+ #[cfg(any(target_os = "freebsd",
+ target_os = "dragonfly",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+ NOKERNINFO;
+ PENDIN;
+ NOFLSH;
+ }
+}
+
+cfg_if!{
+ if #[cfg(any(target_os = "freebsd",
+ target_os = "dragonfly",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "netbsd",
+ target_os = "openbsd"))] {
+ /// Get input baud rate (see
+ /// [cfgetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)).
+ ///
+ /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure.
+ pub fn cfgetispeed(termios: &Termios) -> u32 {
+ let inner_termios = termios.get_libc_termios();
+ unsafe { libc::cfgetispeed(&*inner_termios) as u32 }
+ }
+
+ /// Get output baud rate (see
+ /// [cfgetospeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)).
+ ///
+ /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure.
+ pub fn cfgetospeed(termios: &Termios) -> u32 {
+ let inner_termios = termios.get_libc_termios();
+ unsafe { libc::cfgetospeed(&*inner_termios) as u32 }
+ }
+
+ /// Set input baud rate (see
+ /// [cfsetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)).
+ ///
+ /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure.
+ pub fn cfsetispeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> {
+ let inner_termios = unsafe { termios.get_libc_termios_mut() };
+ let res = unsafe { libc::cfsetispeed(inner_termios, baud.into() as libc::speed_t) };
+ termios.update_wrapper();
+ Errno::result(res).map(drop)
+ }
+
+ /// Set output baud rate (see
+ /// [cfsetospeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)).
+ ///
+ /// `cfsetospeed()` sets the output baud rate in the given termios structure.
+ pub fn cfsetospeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> {
+ let inner_termios = unsafe { termios.get_libc_termios_mut() };
+ let res = unsafe { libc::cfsetospeed(inner_termios, baud.into() as libc::speed_t) };
+ termios.update_wrapper();
+ Errno::result(res).map(drop)
+ }
+
+ /// Set both the input and output baud rates (see
+ /// [termios(3)](https://www.freebsd.org/cgi/man.cgi?query=cfsetspeed)).
+ ///
+ /// `cfsetspeed()` sets the input and output baud rate in the given termios structure. Note that
+ /// this is part of the 4.4BSD standard and not part of POSIX.
+ pub fn cfsetspeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> {
+ let inner_termios = unsafe { termios.get_libc_termios_mut() };
+ let res = unsafe { libc::cfsetspeed(inner_termios, baud.into() as libc::speed_t) };
+ termios.update_wrapper();
+ Errno::result(res).map(drop)
+ }
+ } else {
+ /// Get input baud rate (see
+ /// [cfgetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)).
+ ///
+ /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure.
+ pub fn cfgetispeed(termios: &Termios) -> BaudRate {
+ let inner_termios = termios.get_libc_termios();
+ unsafe { libc::cfgetispeed(&*inner_termios) }.into()
+ }
+
+ /// Get output baud rate (see
+ /// [cfgetospeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)).
+ ///
+ /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure.
+ pub fn cfgetospeed(termios: &Termios) -> BaudRate {
+ let inner_termios = termios.get_libc_termios();
+ unsafe { libc::cfgetospeed(&*inner_termios) }.into()
+ }
+
+ /// Set input baud rate (see
+ /// [cfsetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)).
+ ///
+ /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure.
+ pub fn cfsetispeed(termios: &mut Termios, baud: BaudRate) -> Result<()> {
+ let inner_termios = unsafe { termios.get_libc_termios_mut() };
+ let res = unsafe { libc::cfsetispeed(inner_termios, baud as libc::speed_t) };
+ termios.update_wrapper();
+ Errno::result(res).map(drop)
+ }
+
+ /// Set output baud rate (see
+ /// [cfsetospeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)).
+ ///
+ /// `cfsetospeed()` sets the output baud rate in the given `Termios` structure.
+ pub fn cfsetospeed(termios: &mut Termios, baud: BaudRate) -> Result<()> {
+ let inner_termios = unsafe { termios.get_libc_termios_mut() };
+ let res = unsafe { libc::cfsetospeed(inner_termios, baud as libc::speed_t) };
+ termios.update_wrapper();
+ Errno::result(res).map(drop)
+ }
+
+ /// Set both the input and output baud rates (see
+ /// [termios(3)](https://www.freebsd.org/cgi/man.cgi?query=cfsetspeed)).
+ ///
+ /// `cfsetspeed()` sets the input and output baud rate in the given `Termios` structure. Note that
+ /// this is part of the 4.4BSD standard and not part of POSIX.
+ pub fn cfsetspeed(termios: &mut Termios, baud: BaudRate) -> Result<()> {
+ let inner_termios = unsafe { termios.get_libc_termios_mut() };
+ let res = unsafe { libc::cfsetspeed(inner_termios, baud as libc::speed_t) };
+ termios.update_wrapper();
+ Errno::result(res).map(drop)
+ }
+ }
+}
+
+/// Configures the port to something like the "raw" mode of the old Version 7 terminal driver (see
+/// [termios(3)](http://man7.org/linux/man-pages/man3/termios.3.html)).
+///
+/// `cfmakeraw()` configures the termios structure such that input is available character-by-
+/// character, echoing is disabled, and all special input and output processing is disabled. Note
+/// that this is a non-standard function, but is available on Linux and BSDs.
+pub fn cfmakeraw(termios: &mut Termios) {
+ let inner_termios = unsafe { termios.get_libc_termios_mut() };
+ unsafe {
+ libc::cfmakeraw(inner_termios);
+ }
+ termios.update_wrapper();
+}
+
+/// Configures the port to "sane" mode (like the configuration of a newly created terminal) (see
+/// [tcsetattr(3)](https://www.freebsd.org/cgi/man.cgi?query=tcsetattr)).
+///
+/// Note that this is a non-standard function, available on FreeBSD.
+#[cfg(target_os = "freebsd")]
+pub fn cfmakesane(termios: &mut Termios) {
+ let inner_termios = unsafe { termios.get_libc_termios_mut() };
+ unsafe {
+ libc::cfmakesane(inner_termios);
+ }
+ termios.update_wrapper();
+}
+
+/// Return the configuration of a port
+/// [tcgetattr(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetattr.html)).
+///
+/// `tcgetattr()` returns a `Termios` structure with the current configuration for a port. Modifying
+/// this structure *will not* reconfigure the port, instead the modifications should be done to
+/// the `Termios` structure and then the port should be reconfigured using `tcsetattr()`.
+pub fn tcgetattr(fd: RawFd) -> Result<Termios> {
+ let mut termios: libc::termios = unsafe { mem::uninitialized() };
+
+ let res = unsafe { libc::tcgetattr(fd, &mut termios) };
+
+ Errno::result(res)?;
+
+ Ok(termios.into())
+}
+
+/// Set the configuration for a terminal (see
+/// [tcsetattr(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetattr.html)).
+///
+/// `tcsetattr()` reconfigures the given port based on a given `Termios` structure. This change
+/// takes affect at a time specified by `actions`. Note that this function may return success if
+/// *any* of the parameters were successfully set, not only if all were set successfully.
+pub fn tcsetattr(fd: RawFd, actions: SetArg, termios: &Termios) -> Result<()> {
+ let inner_termios = termios.get_libc_termios();
+ Errno::result(unsafe { libc::tcsetattr(fd, actions as c_int, &*inner_termios) }).map(drop)
+}
+
+/// Block until all output data is written (see
+/// [tcdrain(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcdrain.html)).
+pub fn tcdrain(fd: RawFd) -> Result<()> {
+ Errno::result(unsafe { libc::tcdrain(fd) }).map(drop)
+}
+
+/// Suspend or resume the transmission or reception of data (see
+/// [tcflow(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflow.html)).
+///
+/// `tcflow()` suspends of resumes the transmission or reception of data for the given port
+/// depending on the value of `action`.
+pub fn tcflow(fd: RawFd, action: FlowArg) -> Result<()> {
+ Errno::result(unsafe { libc::tcflow(fd, action as c_int) }).map(drop)
+}
+
+/// Discard data in the output or input queue (see
+/// [tcflush(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflush.html)).
+///
+/// `tcflush()` will discard data for a terminal port in the input queue, output queue, or both
+/// depending on the value of `action`.
+pub fn tcflush(fd: RawFd, action: FlushArg) -> Result<()> {
+ Errno::result(unsafe { libc::tcflush(fd, action as c_int) }).map(drop)
+}
+
+/// Send a break for a specific duration (see
+/// [tcsendbreak(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsendbreak.html)).
+///
+/// When using asynchronous data transmission `tcsendbreak()` will transmit a continuous stream
+/// of zero-valued bits for an implementation-defined duration.
+pub fn tcsendbreak(fd: RawFd, duration: c_int) -> Result<()> {
+ Errno::result(unsafe { libc::tcsendbreak(fd, duration) }).map(drop)
+}
+
+/// Get the session controlled by the given terminal (see
+/// [tcgetsid(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetsid.html)).
+pub fn tcgetsid(fd: RawFd) -> Result<Pid> {
+ let res = unsafe { libc::tcgetsid(fd) };
+
+ Errno::result(res).map(Pid::from_raw)
+}
diff --git a/third_party/rust/nix/src/sys/time.rs b/third_party/rust/nix/src/sys/time.rs
new file mode 100644
index 0000000000..9671f5310a
--- /dev/null
+++ b/third_party/rust/nix/src/sys/time.rs
@@ -0,0 +1,573 @@
+use std::{cmp, fmt, ops};
+use libc::{c_long, timespec, timeval};
+pub use libc::{time_t, suseconds_t};
+
+pub trait TimeValLike: Sized {
+ #[inline]
+ fn zero() -> Self {
+ Self::seconds(0)
+ }
+
+ #[inline]
+ fn hours(hours: i64) -> Self {
+ let secs = hours.checked_mul(SECS_PER_HOUR)
+ .expect("TimeValLike::hours ouf of bounds");
+ Self::seconds(secs)
+ }
+
+ #[inline]
+ fn minutes(minutes: i64) -> Self {
+ let secs = minutes.checked_mul(SECS_PER_MINUTE)
+ .expect("TimeValLike::minutes out of bounds");
+ Self::seconds(secs)
+ }
+
+ fn seconds(seconds: i64) -> Self;
+ fn milliseconds(milliseconds: i64) -> Self;
+ fn microseconds(microseconds: i64) -> Self;
+ fn nanoseconds(nanoseconds: i64) -> Self;
+
+ #[inline]
+ fn num_hours(&self) -> i64 {
+ self.num_seconds() / 3600
+ }
+
+ #[inline]
+ fn num_minutes(&self) -> i64 {
+ self.num_seconds() / 60
+ }
+
+ fn num_seconds(&self) -> i64;
+ fn num_milliseconds(&self) -> i64;
+ fn num_microseconds(&self) -> i64;
+ fn num_nanoseconds(&self) -> i64;
+}
+
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub struct TimeSpec(timespec);
+
+const NANOS_PER_SEC: i64 = 1_000_000_000;
+const SECS_PER_MINUTE: i64 = 60;
+const SECS_PER_HOUR: i64 = 3600;
+
+#[cfg(target_pointer_width = "64")]
+const TS_MAX_SECONDS: i64 = (::std::i64::MAX / NANOS_PER_SEC) - 1;
+
+#[cfg(target_pointer_width = "32")]
+const TS_MAX_SECONDS: i64 = ::std::isize::MAX as i64;
+
+const TS_MIN_SECONDS: i64 = -TS_MAX_SECONDS;
+
+
+impl AsRef<timespec> for TimeSpec {
+ fn as_ref(&self) -> &timespec {
+ &self.0
+ }
+}
+
+impl fmt::Debug for TimeSpec {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_struct("TimeSpec")
+ .field("tv_sec", &self.tv_sec())
+ .field("tv_nsec", &self.tv_nsec())
+ .finish()
+ }
+}
+
+impl PartialEq for TimeSpec {
+ // The implementation of cmp is simplified by assuming that the struct is
+ // normalized. That is, tv_nsec must always be within [0, 1_000_000_000)
+ fn eq(&self, other: &TimeSpec) -> bool {
+ self.tv_sec() == other.tv_sec() && self.tv_nsec() == other.tv_nsec()
+ }
+}
+
+impl Eq for TimeSpec {}
+
+impl Ord for TimeSpec {
+ // The implementation of cmp is simplified by assuming that the struct is
+ // normalized. That is, tv_nsec must always be within [0, 1_000_000_000)
+ fn cmp(&self, other: &TimeSpec) -> cmp::Ordering {
+ if self.tv_sec() == other.tv_sec() {
+ self.tv_nsec().cmp(&other.tv_nsec())
+ } else {
+ self.tv_sec().cmp(&other.tv_sec())
+ }
+ }
+}
+
+impl PartialOrd for TimeSpec {
+ fn partial_cmp(&self, other: &TimeSpec) -> Option<cmp::Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl TimeValLike for TimeSpec {
+ #[inline]
+ fn seconds(seconds: i64) -> TimeSpec {
+ assert!(seconds >= TS_MIN_SECONDS && seconds <= TS_MAX_SECONDS,
+ "TimeSpec out of bounds; seconds={}", seconds);
+ TimeSpec(timespec {tv_sec: seconds as time_t, tv_nsec: 0 })
+ }
+
+ #[inline]
+ fn milliseconds(milliseconds: i64) -> TimeSpec {
+ let nanoseconds = milliseconds.checked_mul(1_000_000)
+ .expect("TimeSpec::milliseconds out of bounds");
+
+ TimeSpec::nanoseconds(nanoseconds)
+ }
+
+ /// Makes a new `TimeSpec` with given number of microseconds.
+ #[inline]
+ fn microseconds(microseconds: i64) -> TimeSpec {
+ let nanoseconds = microseconds.checked_mul(1_000)
+ .expect("TimeSpec::milliseconds out of bounds");
+
+ TimeSpec::nanoseconds(nanoseconds)
+ }
+
+ /// Makes a new `TimeSpec` with given number of nanoseconds.
+ #[inline]
+ fn nanoseconds(nanoseconds: i64) -> TimeSpec {
+ let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC);
+ assert!(secs >= TS_MIN_SECONDS && secs <= TS_MAX_SECONDS,
+ "TimeSpec out of bounds");
+ TimeSpec(timespec {tv_sec: secs as time_t,
+ tv_nsec: nanos as c_long })
+ }
+
+ fn num_seconds(&self) -> i64 {
+ if self.tv_sec() < 0 && self.tv_nsec() > 0 {
+ (self.tv_sec() + 1) as i64
+ } else {
+ self.tv_sec() as i64
+ }
+ }
+
+ fn num_milliseconds(&self) -> i64 {
+ self.num_nanoseconds() / 1_000_000
+ }
+
+ fn num_microseconds(&self) -> i64 {
+ self.num_nanoseconds() / 1_000_000_000
+ }
+
+ fn num_nanoseconds(&self) -> i64 {
+ let secs = self.num_seconds() * 1_000_000_000;
+ let nsec = self.nanos_mod_sec();
+ secs + nsec as i64
+ }
+}
+
+impl TimeSpec {
+ fn nanos_mod_sec(&self) -> c_long {
+ if self.tv_sec() < 0 && self.tv_nsec() > 0 {
+ self.tv_nsec() - NANOS_PER_SEC as c_long
+ } else {
+ self.tv_nsec()
+ }
+ }
+
+ pub fn tv_sec(&self) -> time_t {
+ self.0.tv_sec
+ }
+
+ pub fn tv_nsec(&self) -> c_long {
+ self.0.tv_nsec
+ }
+}
+
+impl ops::Neg for TimeSpec {
+ type Output = TimeSpec;
+
+ fn neg(self) -> TimeSpec {
+ TimeSpec::nanoseconds(-self.num_nanoseconds())
+ }
+}
+
+impl ops::Add for TimeSpec {
+ type Output = TimeSpec;
+
+ fn add(self, rhs: TimeSpec) -> TimeSpec {
+ TimeSpec::nanoseconds(
+ self.num_nanoseconds() + rhs.num_nanoseconds())
+ }
+}
+
+impl ops::Sub for TimeSpec {
+ type Output = TimeSpec;
+
+ fn sub(self, rhs: TimeSpec) -> TimeSpec {
+ TimeSpec::nanoseconds(
+ self.num_nanoseconds() - rhs.num_nanoseconds())
+ }
+}
+
+impl ops::Mul<i32> for TimeSpec {
+ type Output = TimeSpec;
+
+ fn mul(self, rhs: i32) -> TimeSpec {
+ let usec = self.num_nanoseconds().checked_mul(rhs as i64)
+ .expect("TimeSpec multiply out of bounds");
+
+ TimeSpec::nanoseconds(usec)
+ }
+}
+
+impl ops::Div<i32> for TimeSpec {
+ type Output = TimeSpec;
+
+ fn div(self, rhs: i32) -> TimeSpec {
+ let usec = self.num_nanoseconds() / rhs as i64;
+ TimeSpec::nanoseconds(usec)
+ }
+}
+
+impl fmt::Display for TimeSpec {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let (abs, sign) = if self.tv_sec() < 0 {
+ (-*self, "-")
+ } else {
+ (*self, "")
+ };
+
+ let sec = abs.tv_sec();
+
+ write!(f, "{}", sign)?;
+
+ if abs.tv_nsec() == 0 {
+ if abs.tv_sec() == 1 {
+ write!(f, "{} second", sec)?;
+ } else {
+ write!(f, "{} seconds", sec)?;
+ }
+ } else if abs.tv_nsec() % 1_000_000 == 0 {
+ write!(f, "{}.{:03} seconds", sec, abs.tv_nsec() / 1_000_000)?;
+ } else if abs.tv_nsec() % 1_000 == 0 {
+ write!(f, "{}.{:06} seconds", sec, abs.tv_nsec() / 1_000)?;
+ } else {
+ write!(f, "{}.{:09} seconds", sec, abs.tv_nsec())?;
+ }
+
+ Ok(())
+ }
+}
+
+
+
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub struct TimeVal(timeval);
+
+const MICROS_PER_SEC: i64 = 1_000_000;
+
+#[cfg(target_pointer_width = "64")]
+const TV_MAX_SECONDS: i64 = (::std::i64::MAX / MICROS_PER_SEC) - 1;
+
+#[cfg(target_pointer_width = "32")]
+const TV_MAX_SECONDS: i64 = ::std::isize::MAX as i64;
+
+const TV_MIN_SECONDS: i64 = -TV_MAX_SECONDS;
+
+impl AsRef<timeval> for TimeVal {
+ fn as_ref(&self) -> &timeval {
+ &self.0
+ }
+}
+
+impl fmt::Debug for TimeVal {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_struct("TimeVal")
+ .field("tv_sec", &self.tv_sec())
+ .field("tv_usec", &self.tv_usec())
+ .finish()
+ }
+}
+
+impl PartialEq for TimeVal {
+ // The implementation of cmp is simplified by assuming that the struct is
+ // normalized. That is, tv_usec must always be within [0, 1_000_000)
+ fn eq(&self, other: &TimeVal) -> bool {
+ self.tv_sec() == other.tv_sec() && self.tv_usec() == other.tv_usec()
+ }
+}
+
+impl Eq for TimeVal {}
+
+impl Ord for TimeVal {
+ // The implementation of cmp is simplified by assuming that the struct is
+ // normalized. That is, tv_usec must always be within [0, 1_000_000)
+ fn cmp(&self, other: &TimeVal) -> cmp::Ordering {
+ if self.tv_sec() == other.tv_sec() {
+ self.tv_usec().cmp(&other.tv_usec())
+ } else {
+ self.tv_sec().cmp(&other.tv_sec())
+ }
+ }
+}
+
+impl PartialOrd for TimeVal {
+ fn partial_cmp(&self, other: &TimeVal) -> Option<cmp::Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl TimeValLike for TimeVal {
+ #[inline]
+ fn seconds(seconds: i64) -> TimeVal {
+ assert!(seconds >= TV_MIN_SECONDS && seconds <= TV_MAX_SECONDS,
+ "TimeVal out of bounds; seconds={}", seconds);
+ TimeVal(timeval {tv_sec: seconds as time_t, tv_usec: 0 })
+ }
+
+ #[inline]
+ fn milliseconds(milliseconds: i64) -> TimeVal {
+ let microseconds = milliseconds.checked_mul(1_000)
+ .expect("TimeVal::milliseconds out of bounds");
+
+ TimeVal::microseconds(microseconds)
+ }
+
+ /// Makes a new `TimeVal` with given number of microseconds.
+ #[inline]
+ fn microseconds(microseconds: i64) -> TimeVal {
+ let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
+ assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS,
+ "TimeVal out of bounds");
+ TimeVal(timeval {tv_sec: secs as time_t,
+ tv_usec: micros as suseconds_t })
+ }
+
+ /// Makes a new `TimeVal` with given number of nanoseconds. Some precision
+ /// will be lost
+ #[inline]
+ fn nanoseconds(nanoseconds: i64) -> TimeVal {
+ let microseconds = nanoseconds / 1000;
+ let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
+ assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS,
+ "TimeVal out of bounds");
+ TimeVal(timeval {tv_sec: secs as time_t,
+ tv_usec: micros as suseconds_t })
+ }
+
+ fn num_seconds(&self) -> i64 {
+ if self.tv_sec() < 0 && self.tv_usec() > 0 {
+ (self.tv_sec() + 1) as i64
+ } else {
+ self.tv_sec() as i64
+ }
+ }
+
+ fn num_milliseconds(&self) -> i64 {
+ self.num_microseconds() / 1_000
+ }
+
+ fn num_microseconds(&self) -> i64 {
+ let secs = self.num_seconds() * 1_000_000;
+ let usec = self.micros_mod_sec();
+ secs + usec as i64
+ }
+
+ fn num_nanoseconds(&self) -> i64 {
+ self.num_microseconds() * 1_000
+ }
+}
+
+impl TimeVal {
+ fn micros_mod_sec(&self) -> suseconds_t {
+ if self.tv_sec() < 0 && self.tv_usec() > 0 {
+ self.tv_usec() - MICROS_PER_SEC as suseconds_t
+ } else {
+ self.tv_usec()
+ }
+ }
+
+ pub fn tv_sec(&self) -> time_t {
+ self.0.tv_sec
+ }
+
+ pub fn tv_usec(&self) -> suseconds_t {
+ self.0.tv_usec
+ }
+}
+
+impl ops::Neg for TimeVal {
+ type Output = TimeVal;
+
+ fn neg(self) -> TimeVal {
+ TimeVal::microseconds(-self.num_microseconds())
+ }
+}
+
+impl ops::Add for TimeVal {
+ type Output = TimeVal;
+
+ fn add(self, rhs: TimeVal) -> TimeVal {
+ TimeVal::microseconds(
+ self.num_microseconds() + rhs.num_microseconds())
+ }
+}
+
+impl ops::Sub for TimeVal {
+ type Output = TimeVal;
+
+ fn sub(self, rhs: TimeVal) -> TimeVal {
+ TimeVal::microseconds(
+ self.num_microseconds() - rhs.num_microseconds())
+ }
+}
+
+impl ops::Mul<i32> for TimeVal {
+ type Output = TimeVal;
+
+ fn mul(self, rhs: i32) -> TimeVal {
+ let usec = self.num_microseconds().checked_mul(rhs as i64)
+ .expect("TimeVal multiply out of bounds");
+
+ TimeVal::microseconds(usec)
+ }
+}
+
+impl ops::Div<i32> for TimeVal {
+ type Output = TimeVal;
+
+ fn div(self, rhs: i32) -> TimeVal {
+ let usec = self.num_microseconds() / rhs as i64;
+ TimeVal::microseconds(usec)
+ }
+}
+
+impl fmt::Display for TimeVal {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let (abs, sign) = if self.tv_sec() < 0 {
+ (-*self, "-")
+ } else {
+ (*self, "")
+ };
+
+ let sec = abs.tv_sec();
+
+ write!(f, "{}", sign)?;
+
+ if abs.tv_usec() == 0 {
+ if abs.tv_sec() == 1 {
+ write!(f, "{} second", sec)?;
+ } else {
+ write!(f, "{} seconds", sec)?;
+ }
+ } else if abs.tv_usec() % 1000 == 0 {
+ write!(f, "{}.{:03} seconds", sec, abs.tv_usec() / 1000)?;
+ } else {
+ write!(f, "{}.{:06} seconds", sec, abs.tv_usec())?;
+ }
+
+ Ok(())
+ }
+}
+
+#[inline]
+fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
+ (div_floor_64(this, other), mod_floor_64(this, other))
+}
+
+#[inline]
+fn div_floor_64(this: i64, other: i64) -> i64 {
+ match div_rem_64(this, other) {
+ (d, r) if (r > 0 && other < 0)
+ || (r < 0 && other > 0) => d - 1,
+ (d, _) => d,
+ }
+}
+
+#[inline]
+fn mod_floor_64(this: i64, other: i64) -> i64 {
+ match this % other {
+ r if (r > 0 && other < 0)
+ || (r < 0 && other > 0) => r + other,
+ r => r,
+ }
+}
+
+#[inline]
+fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
+ (this / other, this % other)
+}
+
+#[cfg(test)]
+mod test {
+ use super::{TimeSpec, TimeVal, TimeValLike};
+
+ #[test]
+ pub fn test_timespec() {
+ assert!(TimeSpec::seconds(1) != TimeSpec::zero());
+ assert_eq!(TimeSpec::seconds(1) + TimeSpec::seconds(2),
+ TimeSpec::seconds(3));
+ assert_eq!(TimeSpec::minutes(3) + TimeSpec::seconds(2),
+ TimeSpec::seconds(182));
+ }
+
+ #[test]
+ pub fn test_timespec_neg() {
+ let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123);
+ let b = TimeSpec::seconds(-1) + TimeSpec::nanoseconds(-123);
+
+ assert_eq!(a, -b);
+ }
+
+ #[test]
+ pub fn test_timespec_ord() {
+ assert!(TimeSpec::seconds(1) == TimeSpec::nanoseconds(1_000_000_000));
+ assert!(TimeSpec::seconds(1) < TimeSpec::nanoseconds(1_000_000_001));
+ assert!(TimeSpec::seconds(1) > TimeSpec::nanoseconds(999_999_999));
+ assert!(TimeSpec::seconds(-1) < TimeSpec::nanoseconds(-999_999_999));
+ assert!(TimeSpec::seconds(-1) > TimeSpec::nanoseconds(-1_000_000_001));
+ }
+
+ #[test]
+ pub fn test_timespec_fmt() {
+ assert_eq!(TimeSpec::zero().to_string(), "0 seconds");
+ assert_eq!(TimeSpec::seconds(42).to_string(), "42 seconds");
+ assert_eq!(TimeSpec::milliseconds(42).to_string(), "0.042 seconds");
+ assert_eq!(TimeSpec::microseconds(42).to_string(), "0.000042 seconds");
+ assert_eq!(TimeSpec::nanoseconds(42).to_string(), "0.000000042 seconds");
+ assert_eq!(TimeSpec::seconds(-86401).to_string(), "-86401 seconds");
+ }
+
+ #[test]
+ pub fn test_timeval() {
+ assert!(TimeVal::seconds(1) != TimeVal::zero());
+ assert_eq!(TimeVal::seconds(1) + TimeVal::seconds(2),
+ TimeVal::seconds(3));
+ assert_eq!(TimeVal::minutes(3) + TimeVal::seconds(2),
+ TimeVal::seconds(182));
+ }
+
+ #[test]
+ pub fn test_timeval_ord() {
+ assert!(TimeVal::seconds(1) == TimeVal::microseconds(1_000_000));
+ assert!(TimeVal::seconds(1) < TimeVal::microseconds(1_000_001));
+ assert!(TimeVal::seconds(1) > TimeVal::microseconds(999_999));
+ assert!(TimeVal::seconds(-1) < TimeVal::microseconds(-999_999));
+ assert!(TimeVal::seconds(-1) > TimeVal::microseconds(-1_000_001));
+ }
+
+ #[test]
+ pub fn test_timeval_neg() {
+ let a = TimeVal::seconds(1) + TimeVal::microseconds(123);
+ let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123);
+
+ assert_eq!(a, -b);
+ }
+
+ #[test]
+ pub fn test_timeval_fmt() {
+ assert_eq!(TimeVal::zero().to_string(), "0 seconds");
+ assert_eq!(TimeVal::seconds(42).to_string(), "42 seconds");
+ assert_eq!(TimeVal::milliseconds(42).to_string(), "0.042 seconds");
+ assert_eq!(TimeVal::microseconds(42).to_string(), "0.000042 seconds");
+ assert_eq!(TimeVal::nanoseconds(1402).to_string(), "0.000001 seconds");
+ assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds");
+ }
+}
diff --git a/third_party/rust/nix/src/sys/uio.rs b/third_party/rust/nix/src/sys/uio.rs
new file mode 100644
index 0000000000..b01fc7e6a9
--- /dev/null
+++ b/third_party/rust/nix/src/sys/uio.rs
@@ -0,0 +1,195 @@
+// Silence invalid warnings due to rust-lang/rust#16719
+#![allow(improper_ctypes)]
+
+use Result;
+use errno::Errno;
+use libc::{self, c_int, c_void, size_t, off_t};
+use std::marker::PhantomData;
+use std::os::unix::io::RawFd;
+
+pub fn writev(fd: RawFd, iov: &[IoVec<&[u8]>]) -> Result<usize> {
+ let res = unsafe { libc::writev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) };
+
+ Errno::result(res).map(|r| r as usize)
+}
+
+pub fn readv(fd: RawFd, iov: &mut [IoVec<&mut [u8]>]) -> Result<usize> {
+ let res = unsafe { libc::readv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) };
+
+ Errno::result(res).map(|r| r as usize)
+}
+
+/// Write to `fd` at `offset` from buffers in `iov`.
+///
+/// Buffers in `iov` will be written in order until all buffers have been written
+/// or an error occurs. The file offset is not changed.
+///
+/// See also: [`writev`](fn.writev.html) and [`pwrite`](fn.pwrite.html)
+#[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+pub fn pwritev(fd: RawFd, iov: &[IoVec<&[u8]>],
+ offset: off_t) -> Result<usize> {
+ let res = unsafe {
+ libc::pwritev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset)
+ };
+
+ Errno::result(res).map(|r| r as usize)
+}
+
+/// Read from `fd` at `offset` filling buffers in `iov`.
+///
+/// Buffers in `iov` will be filled in order until all buffers have been filled,
+/// no more bytes are available, or an error occurs. The file offset is not
+/// changed.
+///
+/// See also: [`readv`](fn.readv.html) and [`pread`](fn.pread.html)
+#[cfg(any(target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "netbsd",
+ target_os = "openbsd"))]
+pub fn preadv(fd: RawFd, iov: &[IoVec<&mut [u8]>],
+ offset: off_t) -> Result<usize> {
+ let res = unsafe {
+ libc::preadv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset)
+ };
+
+ Errno::result(res).map(|r| r as usize)
+}
+
+pub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result<usize> {
+ let res = unsafe {
+ libc::pwrite(fd, buf.as_ptr() as *const c_void, buf.len() as size_t,
+ offset)
+ };
+
+ Errno::result(res).map(|r| r as usize)
+}
+
+pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result<usize>{
+ let res = unsafe {
+ libc::pread(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t,
+ offset)
+ };
+
+ Errno::result(res).map(|r| r as usize)
+}
+
+/// A slice of memory in a remote process, starting at address `base`
+/// and consisting of `len` bytes.
+///
+/// This is the same underlying C structure as [`IoVec`](struct.IoVec.html),
+/// except that it refers to memory in some other process, and is
+/// therefore not represented in Rust by an actual slice as `IoVec` is. It
+/// is used with [`process_vm_readv`](fn.process_vm_readv.html)
+/// and [`process_vm_writev`](fn.process_vm_writev.html).
+#[cfg(target_os = "linux")]
+#[repr(C)]
+#[derive(Clone, Copy)]
+#[allow(missing_debug_implementations)]
+pub struct RemoteIoVec {
+ /// The starting address of this slice (`iov_base`).
+ pub base: usize,
+ /// The number of bytes in this slice (`iov_len`).
+ pub len: usize,
+}
+
+/// Write data directly to another process's virtual memory
+/// (see [`process_vm_writev`(2)]).
+///
+/// `local_iov` is a list of [`IoVec`]s containing the data to be written,
+/// and `remote_iov` is a list of [`RemoteIoVec`]s identifying where the
+/// data should be written in the target process. On success, returns the
+/// number of bytes written, which will always be a whole
+/// number of `remote_iov` chunks.
+///
+/// This requires the same permissions as debugging the process using
+/// [ptrace]: you must either be a privileged process (with
+/// `CAP_SYS_PTRACE`), or you must be running as the same user as the
+/// target process and the OS must have unprivileged debugging enabled.
+///
+/// This function is only available on Linux.
+///
+/// [`process_vm_writev`(2)]: http://man7.org/linux/man-pages/man2/process_vm_writev.2.html
+/// [ptrace]: ../ptrace/index.html
+/// [`IoVec`]: struct.IoVec.html
+/// [`RemoteIoVec`]: struct.RemoteIoVec.html
+// #[cfg(target_os = "linux")]
+// pub fn process_vm_writev(pid: ::unistd::Pid, local_iov: &[IoVec<&[u8]>], remote_iov: &[RemoteIoVec]) -> Result<usize> {
+// let res = unsafe {
+// libc::process_vm_writev(pid.into(),
+// local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong,
+// remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0)
+// };
+
+// Errno::result(res).map(|r| r as usize)
+// }
+
+/// Read data directly from another process's virtual memory
+/// (see [`process_vm_readv`(2)]).
+///
+/// `local_iov` is a list of [`IoVec`]s containing the buffer to copy
+/// data into, and `remote_iov` is a list of [`RemoteIoVec`]s identifying
+/// where the source data is in the target process. On success,
+/// returns the number of bytes written, which will always be a whole
+/// number of `remote_iov` chunks.
+///
+/// This requires the same permissions as debugging the process using
+/// [`ptrace`]: you must either be a privileged process (with
+/// `CAP_SYS_PTRACE`), or you must be running as the same user as the
+/// target process and the OS must have unprivileged debugging enabled.
+///
+/// This function is only available on Linux.
+///
+/// [`process_vm_readv`(2)]: http://man7.org/linux/man-pages/man2/process_vm_readv.2.html
+/// [`ptrace`]: ../ptrace/index.html
+/// [`IoVec`]: struct.IoVec.html
+/// [`RemoteIoVec`]: struct.RemoteIoVec.html
+// #[cfg(any(target_os = "linux"))]
+// pub fn process_vm_readv(pid: ::unistd::Pid, local_iov: &[IoVec<&mut [u8]>], remote_iov: &[RemoteIoVec]) -> Result<usize> {
+// let res = unsafe {
+// libc::process_vm_readv(pid.into(),
+// local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong,
+// remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0)
+// };
+
+// Errno::result(res).map(|r| r as usize)
+// }
+
+#[repr(C)]
+#[allow(missing_debug_implementations)]
+pub struct IoVec<T>(libc::iovec, PhantomData<T>);
+
+impl<T> IoVec<T> {
+ #[inline]
+ pub fn as_slice(&self) -> &[u8] {
+ use std::slice;
+
+ unsafe {
+ slice::from_raw_parts(
+ self.0.iov_base as *const u8,
+ self.0.iov_len as usize)
+ }
+ }
+}
+
+impl<'a> IoVec<&'a [u8]> {
+ pub fn from_slice(buf: &'a [u8]) -> IoVec<&'a [u8]> {
+ IoVec(libc::iovec {
+ iov_base: buf.as_ptr() as *mut c_void,
+ iov_len: buf.len() as size_t,
+ }, PhantomData)
+ }
+}
+
+impl<'a> IoVec<&'a mut [u8]> {
+ pub fn from_mut_slice(buf: &'a mut [u8]) -> IoVec<&'a mut [u8]> {
+ IoVec(libc::iovec {
+ iov_base: buf.as_ptr() as *mut c_void,
+ iov_len: buf.len() as size_t,
+ }, PhantomData)
+ }
+}
diff --git a/third_party/rust/nix/src/sys/utsname.rs b/third_party/rust/nix/src/sys/utsname.rs
new file mode 100644
index 0000000000..e33d0739a0
--- /dev/null
+++ b/third_party/rust/nix/src/sys/utsname.rs
@@ -0,0 +1,68 @@
+use std::mem;
+use libc::{self, c_char};
+use std::ffi::CStr;
+use std::str::from_utf8_unchecked;
+
+#[repr(C)]
+#[derive(Clone, Copy)]
+#[allow(missing_debug_implementations)]
+pub struct UtsName(libc::utsname);
+
+impl UtsName {
+ pub fn sysname(&self) -> &str {
+ to_str(&(&self.0.sysname as *const c_char ) as *const *const c_char)
+ }
+
+ pub fn nodename(&self) -> &str {
+ to_str(&(&self.0.nodename as *const c_char ) as *const *const c_char)
+ }
+
+ pub fn release(&self) -> &str {
+ to_str(&(&self.0.release as *const c_char ) as *const *const c_char)
+ }
+
+ pub fn version(&self) -> &str {
+ to_str(&(&self.0.version as *const c_char ) as *const *const c_char)
+ }
+
+ pub fn machine(&self) -> &str {
+ to_str(&(&self.0.machine as *const c_char ) as *const *const c_char)
+ }
+}
+
+pub fn uname() -> UtsName {
+ unsafe {
+ let mut ret: UtsName = mem::uninitialized();
+ libc::uname(&mut ret.0);
+ ret
+ }
+}
+
+#[inline]
+fn to_str<'a>(s: *const *const c_char) -> &'a str {
+ unsafe {
+ let res = CStr::from_ptr(*s).to_bytes();
+ from_utf8_unchecked(res)
+ }
+}
+
+#[cfg(test)]
+mod test {
+ #[cfg(target_os = "linux")]
+ #[test]
+ pub fn test_uname_linux() {
+ assert_eq!(super::uname().sysname(), "Linux");
+ }
+
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ #[test]
+ pub fn test_uname_darwin() {
+ assert_eq!(super::uname().sysname(), "Darwin");
+ }
+
+ #[cfg(target_os = "freebsd")]
+ #[test]
+ pub fn test_uname_freebsd() {
+ assert_eq!(super::uname().sysname(), "FreeBSD");
+ }
+}
diff --git a/third_party/rust/nix/src/sys/wait.rs b/third_party/rust/nix/src/sys/wait.rs
new file mode 100644
index 0000000000..3f99757daf
--- /dev/null
+++ b/third_party/rust/nix/src/sys/wait.rs
@@ -0,0 +1,239 @@
+use libc::{self, c_int};
+use Result;
+use errno::Errno;
+use unistd::Pid;
+
+use sys::signal::Signal;
+
+libc_bitflags!(
+ pub struct WaitPidFlag: c_int {
+ WNOHANG;
+ WUNTRACED;
+ #[cfg(any(target_os = "android",
+ target_os = "freebsd",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd"))]
+ WEXITED;
+ WCONTINUED;
+ #[cfg(any(target_os = "android",
+ target_os = "freebsd",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd"))]
+ WSTOPPED;
+ /// Don't reap, just poll status.
+ #[cfg(any(target_os = "android",
+ target_os = "freebsd",
+ target_os = "haiku",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd"))]
+ WNOWAIT;
+ /// Don't wait on children of other threads in this group
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ __WNOTHREAD;
+ /// Wait on all children, regardless of type
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ __WALL;
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ __WCLONE;
+ }
+);
+
+/// Possible return values from `wait()` or `waitpid()`.
+///
+/// Each status (other than `StillAlive`) describes a state transition
+/// in a child process `Pid`, such as the process exiting or stopping,
+/// plus additional data about the transition if any.
+///
+/// Note that there are two Linux-specific enum variants, `PtraceEvent`
+/// and `PtraceSyscall`. Portable code should avoid exhaustively
+/// matching on `WaitStatus`.
+#[derive(Eq, PartialEq, Clone, Copy, Debug)]
+pub enum WaitStatus {
+ /// The process exited normally (as with `exit()` or returning from
+ /// `main`) with the given exit code. This case matches the C macro
+ /// `WIFEXITED(status)`; the second field is `WEXITSTATUS(status)`.
+ Exited(Pid, i32),
+ /// The process was killed by the given signal. The third field
+ /// indicates whether the signal generated a core dump. This case
+ /// matches the C macro `WIFSIGNALED(status)`; the last two fields
+ /// correspond to `WTERMSIG(status)` and `WCOREDUMP(status)`.
+ Signaled(Pid, Signal, bool),
+ /// The process is alive, but was stopped by the given signal. This
+ /// is only reported if `WaitPidFlag::WUNTRACED` was passed. This
+ /// case matches the C macro `WIFSTOPPED(status)`; the second field
+ /// is `WSTOPSIG(status)`.
+ Stopped(Pid, Signal),
+ /// The traced process was stopped by a `PTRACE_EVENT_*` event. See
+ /// [`nix::sys::ptrace`] and [`ptrace`(2)] for more information. All
+ /// currently-defined events use `SIGTRAP` as the signal; the third
+ /// field is the `PTRACE_EVENT_*` value of the event.
+ ///
+ /// [`nix::sys::ptrace`]: ../ptrace/index.html
+ /// [`ptrace`(2)]: http://man7.org/linux/man-pages/man2/ptrace.2.html
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ PtraceEvent(Pid, Signal, c_int),
+ /// The traced process was stopped by execution of a system call,
+ /// and `PTRACE_O_TRACESYSGOOD` is in effect. See [`ptrace`(2)] for
+ /// more information.
+ ///
+ /// [`ptrace`(2)]: http://man7.org/linux/man-pages/man2/ptrace.2.html
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ PtraceSyscall(Pid),
+ /// The process was previously stopped but has resumed execution
+ /// after receiving a `SIGCONT` signal. This is only reported if
+ /// `WaitPidFlag::WCONTINUED` was passed. This case matches the C
+ /// macro `WIFCONTINUED(status)`.
+ Continued(Pid),
+ /// There are currently no state changes to report in any awaited
+ /// child process. This is only returned if `WaitPidFlag::WNOHANG`
+ /// was used (otherwise `wait()` or `waitpid()` would block until
+ /// there was something to report).
+ StillAlive,
+}
+
+impl WaitStatus {
+ /// Extracts the PID from the WaitStatus unless it equals StillAlive.
+ pub fn pid(&self) -> Option<Pid> {
+ use self::WaitStatus::*;
+ match *self {
+ Exited(p, _) | Signaled(p, _, _) |
+ Stopped(p, _) | Continued(p) => Some(p),
+ StillAlive => None,
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ PtraceEvent(p, _, _) | PtraceSyscall(p) => Some(p),
+ }
+ }
+}
+
+fn exited(status: i32) -> bool {
+ unsafe { libc::WIFEXITED(status) }
+}
+
+fn exit_status(status: i32) -> i32 {
+ unsafe { libc::WEXITSTATUS(status) }
+}
+
+fn signaled(status: i32) -> bool {
+ unsafe { libc::WIFSIGNALED(status) }
+}
+
+fn term_signal(status: i32) -> Result<Signal> {
+ Signal::from_c_int(unsafe { libc::WTERMSIG(status) })
+}
+
+fn dumped_core(status: i32) -> bool {
+ unsafe { libc::WCOREDUMP(status) }
+}
+
+fn stopped(status: i32) -> bool {
+ unsafe { libc::WIFSTOPPED(status) }
+}
+
+fn stop_signal(status: i32) -> Result<Signal> {
+ Signal::from_c_int(unsafe { libc::WSTOPSIG(status) })
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+fn syscall_stop(status: i32) -> bool {
+ // From ptrace(2), setting PTRACE_O_TRACESYSGOOD has the effect
+ // of delivering SIGTRAP | 0x80 as the signal number for syscall
+ // stops. This allows easily distinguishing syscall stops from
+ // genuine SIGTRAP signals.
+ unsafe { libc::WSTOPSIG(status) == libc::SIGTRAP | 0x80 }
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+fn stop_additional(status: i32) -> c_int {
+ (status >> 16) as c_int
+}
+
+fn continued(status: i32) -> bool {
+ unsafe { libc::WIFCONTINUED(status) }
+}
+
+impl WaitStatus {
+ /// Convert a raw `wstatus` as returned by `waitpid`/`wait` into a `WaitStatus`
+ ///
+ /// # Errors
+ ///
+ /// Returns an `Error` corresponding to `EINVAL` for invalid status values.
+ ///
+ /// # Examples
+ ///
+ /// Convert a `wstatus` obtained from `libc::waitpid` into a `WaitStatus`:
+ ///
+ /// ```
+ /// use nix::sys::wait::WaitStatus;
+ /// use nix::sys::signal::Signal;
+ /// let pid = nix::unistd::Pid::from_raw(1);
+ /// let status = WaitStatus::from_raw(pid, 0x0002);
+ /// assert_eq!(status, Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false)));
+ /// ```
+ pub fn from_raw(pid: Pid, status: i32) -> Result<WaitStatus> {
+ Ok(if exited(status) {
+ WaitStatus::Exited(pid, exit_status(status))
+ } else if signaled(status) {
+ WaitStatus::Signaled(pid, term_signal(status)?, dumped_core(status))
+ } else if stopped(status) {
+ cfg_if! {
+ if #[cfg(any(target_os = "android", target_os = "linux"))] {
+ fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> {
+ let status_additional = stop_additional(status);
+ Ok(if syscall_stop(status) {
+ WaitStatus::PtraceSyscall(pid)
+ } else if status_additional == 0 {
+ WaitStatus::Stopped(pid, stop_signal(status)?)
+ } else {
+ WaitStatus::PtraceEvent(pid, stop_signal(status)?,
+ stop_additional(status))
+ })
+ }
+ } else {
+ fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> {
+ Ok(WaitStatus::Stopped(pid, stop_signal(status)?))
+ }
+ }
+ }
+ return decode_stopped(pid, status);
+ } else {
+ assert!(continued(status));
+ WaitStatus::Continued(pid)
+ })
+ }
+}
+
+pub fn waitpid<P: Into<Option<Pid>>>(pid: P, options: Option<WaitPidFlag>) -> Result<WaitStatus> {
+ use self::WaitStatus::*;
+
+ let mut status: i32 = 0;
+
+ let option_bits = match options {
+ Some(bits) => bits.bits(),
+ None => 0,
+ };
+
+ let res = unsafe {
+ libc::waitpid(
+ pid.into().unwrap_or(Pid::from_raw(-1)).into(),
+ &mut status as *mut c_int,
+ option_bits,
+ )
+ };
+
+ match Errno::result(res)? {
+ 0 => Ok(StillAlive),
+ res => WaitStatus::from_raw(Pid::from_raw(res), status),
+ }
+}
+
+pub fn wait() -> Result<WaitStatus> {
+ waitpid(None, None)
+}