Upgrade rust/crates/nix to 0.22.0

Test: make
Change-Id: I3997c62033aaf9734073fd1aa6e6da0d9c522034
diff --git a/test/common/mod.rs b/test/common/mod.rs
index 8a79d6a..cdc3258 100644
--- a/test/common/mod.rs
+++ b/test/common/mod.rs
@@ -31,6 +31,20 @@
     }
 }
 
+/// Skip the test if we don't have the ability to mount file systems.
+#[cfg(target_os = "freebsd")]
+#[macro_export] macro_rules! require_mount {
+    ($name:expr) => {
+        use ::sysctl::CtlValue;
+        use nix::unistd::Uid;
+
+        if !Uid::current().is_root() && CtlValue::Int(0) == ::sysctl::value("vfs.usermount").unwrap()
+        {
+            skip!("{} requires the ability to mount file systems. Skipping test.", $name);
+        }
+    }
+}
+
 #[cfg(any(target_os = "linux", target_os= "android"))]
 #[macro_export] macro_rules! skip_if_cirrus {
     ($reason:expr) => {
diff --git a/test/sys/test_aio.rs b/test/sys/test_aio.rs
index 753f118..3208410 100644
--- a/test/sys/test_aio.rs
+++ b/test/sys/test_aio.rs
@@ -142,9 +142,7 @@
 }
 
 #[test]
-#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
-// On Travis, aio_suspend hits an assertion within glibc.  This is either a bug
-// in Travis's version of glibc or Linux.  Either way, we must skip the test.
+// On Cirrus on Linux, this test fails due to a glibc bug.
 // https://github.com/nix-rust/nix/issues/1099
 #[cfg_attr(target_os = "linux", ignore)]
 // On Cirrus, aio_suspend is failing with EINVAL
@@ -179,7 +177,7 @@
             let cbbuf = [wcb.as_ref(), rcb.as_ref()];
             let r = aio_suspend(&cbbuf[..], Some(timeout));
             match r {
-                Err(Error::Sys(Errno::EINTR)) => continue,
+                Err(Errno::EINTR) => continue,
                 Err(e) => panic!("aio_suspend returned {:?}", e),
                 Ok(_) => ()
             };
diff --git a/test/sys/test_aio_drop.rs b/test/sys/test_aio_drop.rs
index 784ee3e..71a2183 100644
--- a/test/sys/test_aio_drop.rs
+++ b/test/sys/test_aio_drop.rs
@@ -9,7 +9,6 @@
               target_os = "macos",
               target_os = "freebsd",
               target_os = "netbsd")))]
-#[cfg_attr(target_env = "gnu", ignore = "Occasionally fails in Travis; glibc bug suspected")]
 fn test_drop() {
     use nix::sys::aio::*;
     use nix::sys::signal::*;
diff --git a/test/sys/test_epoll.rs b/test/sys/test_epoll.rs
index e0dc513..57bc484 100644
--- a/test/sys/test_epoll.rs
+++ b/test/sys/test_epoll.rs
@@ -8,11 +8,11 @@
     let efd = epoll_create1(EpollCreateFlags::empty()).unwrap();
     let result = epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None);
     assert!(result.is_err());
-    assert_eq!(result.unwrap_err(), Error::Sys(Errno::ENOENT));
+    assert_eq!(result.unwrap_err(), Error::from(Errno::ENOENT));
 
     let result = epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, None);
     assert!(result.is_err());
-    assert_eq!(result.unwrap_err(), Error::Sys(Errno::EINVAL));
+    assert_eq!(result.unwrap_err(), Error::from(Errno::EINVAL));
 }
 
 #[test]
diff --git a/test/sys/test_inotify.rs b/test/sys/test_inotify.rs
index a8ead46..121b726 100644
--- a/test/sys/test_inotify.rs
+++ b/test/sys/test_inotify.rs
@@ -14,7 +14,7 @@
     instance.add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS).unwrap();
 
     let events = instance.read_events();
-    assert_eq!(events.unwrap_err(), Error::Sys(Errno::EAGAIN));
+    assert_eq!(events.unwrap_err(), Error::from(Errno::EAGAIN));
 
     File::create(tempdir.path().join("test")).unwrap();
 
@@ -31,7 +31,7 @@
     instance.add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS).unwrap();
 
     let events = instance.read_events();
-    assert_eq!(events.unwrap_err(), Error::Sys(Errno::EAGAIN));
+    assert_eq!(events.unwrap_err(), Error::from(Errno::EAGAIN));
 
     File::create(tempdir.path().join("test")).unwrap();
     rename(tempdir.path().join("test"), tempdir.path().join("test2")).unwrap();
diff --git a/test/sys/test_ioctl.rs b/test/sys/test_ioctl.rs
index ddb8696..236d242 100644
--- a/test/sys/test_ioctl.rs
+++ b/test/sys/test_ioctl.rs
@@ -167,15 +167,14 @@
     use tempfile::tempfile;
     use libc::{TCGETS, TCSBRK, TCSETS, TIOCNXCL, termios};
 
-    use nix::Error::Sys;
-    use nix::errno::Errno::{ENOTTY, ENOSYS};
+    use nix::errno::Errno;
 
     ioctl_none_bad!(tiocnxcl, TIOCNXCL);
     #[test]
     fn test_ioctl_none_bad() {
         let file = tempfile().unwrap();
         let res = unsafe { tiocnxcl(file.as_raw_fd()) };
-        assert_eq!(res, Err(Sys(ENOTTY)));
+        assert_eq!(res, Err(Errno::ENOTTY));
     }
 
     ioctl_read_bad!(tcgets, TCGETS, termios);
@@ -184,7 +183,7 @@
         let file = tempfile().unwrap();
         let mut termios = unsafe { mem::zeroed() };
         let res = unsafe { tcgets(file.as_raw_fd(), &mut termios) };
-        assert_eq!(res, Err(Sys(ENOTTY)));
+        assert_eq!(res, Err(Errno::ENOTTY));
     }
 
     ioctl_write_int_bad!(tcsbrk, TCSBRK);
@@ -192,7 +191,7 @@
     fn test_ioctl_write_int_bad() {
         let file = tempfile().unwrap();
         let res = unsafe { tcsbrk(file.as_raw_fd(), 0) };
-        assert_eq!(res, Err(Sys(ENOTTY)));
+        assert_eq!(res, Err(Errno::ENOTTY));
     }
 
     ioctl_write_ptr_bad!(tcsets, TCSETS, termios);
@@ -201,7 +200,7 @@
         let file = tempfile().unwrap();
         let termios: termios = unsafe { mem::zeroed() };
         let res = unsafe { tcsets(file.as_raw_fd(), &termios) };
-        assert_eq!(res, Err(Sys(ENOTTY)));
+        assert_eq!(res, Err(Errno::ENOTTY));
     }
 
     // FIXME: Find a suitable example for `ioctl_readwrite_bad`
@@ -212,7 +211,7 @@
     fn test_ioctl_none() {
         let file = tempfile().unwrap();
         let res = unsafe { log_status(file.as_raw_fd()) };
-        assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
+        assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
     }
 
     #[repr(C)]
@@ -231,7 +230,7 @@
         let file = tempfile().unwrap();
         let data: v4l2_audio = unsafe { mem::zeroed() };
         let res = unsafe { s_audio(file.as_raw_fd(), &data) };
-        assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
+        assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
     }
 
     // From linux/net/bluetooth/hci_sock.h
@@ -242,7 +241,7 @@
     fn test_ioctl_write_int() {
         let file = tempfile().unwrap();
         let res = unsafe { hcidevup(file.as_raw_fd(), 0) };
-        assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
+        assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
     }
 
     // From linux/videodev2.h
@@ -252,7 +251,7 @@
         let file = tempfile().unwrap();
         let mut data: v4l2_audio = unsafe { mem::zeroed() };
         let res = unsafe { g_audio(file.as_raw_fd(), &mut data) };
-        assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
+        assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
     }
 
     // From linux/videodev2.h
@@ -262,7 +261,7 @@
         let file = tempfile().unwrap();
         let mut data: v4l2_audio = unsafe { mem::zeroed() };
         let res = unsafe { enum_audio(file.as_raw_fd(), &mut data) };
-        assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
+        assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
     }
 
     // FIXME: Find a suitable example for `ioctl_read_buf`.
@@ -288,7 +287,7 @@
         let file = tempfile().unwrap();
         let data: [spi_ioc_transfer; 4] = unsafe { mem::zeroed() };
         let res = unsafe { spi_ioc_message(file.as_raw_fd(), &data[..]) };
-        assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
+        assert!(res == Err(Errno::ENOTTY) || res == Err(Errno::ENOSYS));
     }
 
     // FIXME: Find a suitable example for `ioctl_readwrite_buf`.
@@ -302,8 +301,7 @@
     use tempfile::tempfile;
     use libc::termios;
 
-    use nix::Error::Sys;
-    use nix::errno::Errno::ENOTTY;
+    use nix::errno::Errno;
 
     // From sys/sys/ttycom.h
     const TTY_IOC_MAGIC: u8 = b't';
@@ -316,7 +314,7 @@
     fn test_ioctl_none() {
         let file = tempfile().unwrap();
         let res = unsafe { tiocnxcl(file.as_raw_fd()) };
-        assert_eq!(res, Err(Sys(ENOTTY)));
+        assert_eq!(res, Err(Errno::ENOTTY));
     }
 
     ioctl_read!(tiocgeta, TTY_IOC_MAGIC, TTY_IOC_TYPE_GETA, termios);
@@ -325,7 +323,7 @@
         let file = tempfile().unwrap();
         let mut termios = unsafe { mem::zeroed() };
         let res = unsafe { tiocgeta(file.as_raw_fd(), &mut termios) };
-        assert_eq!(res, Err(Sys(ENOTTY)));
+        assert_eq!(res, Err(Errno::ENOTTY));
     }
 
     ioctl_write_ptr!(tiocseta, TTY_IOC_MAGIC, TTY_IOC_TYPE_SETA, termios);
@@ -334,6 +332,6 @@
         let file = tempfile().unwrap();
         let termios: termios = unsafe { mem::zeroed() };
         let res = unsafe { tiocseta(file.as_raw_fd(), &termios) };
-        assert_eq!(res, Err(Sys(ENOTTY)));
+        assert_eq!(res, Err(Errno::ENOTTY));
     }
 }
diff --git a/test/sys/test_lio_listio_resubmit.rs b/test/sys/test_lio_listio_resubmit.rs
index 6b33aa4..c907789 100644
--- a/test/sys/test_lio_listio_resubmit.rs
+++ b/test/sys/test_lio_listio_resubmit.rs
@@ -4,7 +4,6 @@
 // we must disable the test here rather than in Cargo.toml
 #![cfg(target_os = "freebsd")]
 
-use nix::Error;
 use nix::errno::*;
 use nix::libc::off_t;
 use nix::sys::aio::*;
@@ -25,7 +24,7 @@
             let e = liocb.error(j);
             match e {
                 Ok(()) => break,
-                Err(Error::Sys(Errno::EINPROGRESS)) =>
+                Err(Errno::EINPROGRESS) =>
                     thread::sleep(time::Duration::from_millis(10)),
                 Err(x) => panic!("aio_error({:?})", x)
             }
@@ -82,9 +81,9 @@
         }
         let mut liocb = builder.finish();
         let mut err = liocb.listio(LioMode::LIO_NOWAIT, SigevNotify::SigevNone);
-        while err == Err(Error::Sys(Errno::EIO)) ||
-              err == Err(Error::Sys(Errno::EAGAIN)) ||
-              err == Err(Error::Sys(Errno::EINTR)) {
+        while err == Err(Errno::EIO) ||
+              err == Err(Errno::EAGAIN) ||
+              err == Err(Errno::EINTR) {
             // 
             thread::sleep(time::Duration::from_millis(10));
             resubmit_count += 1;
diff --git a/test/sys/test_ptrace.rs b/test/sys/test_ptrace.rs
index b9793b3..985945d 100644
--- a/test/sys/test_ptrace.rs
+++ b/test/sys/test_ptrace.rs
@@ -1,4 +1,3 @@
-use nix::Error;
 use nix::errno::Errno;
 use nix::unistd::getpid;
 use nix::sys::ptrace;
@@ -16,8 +15,8 @@
     // FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS
     require_capability!(CAP_SYS_PTRACE);
     let err = ptrace::attach(getpid()).unwrap_err();
-    assert!(err == Error::Sys(Errno::EPERM) || err == Error::Sys(Errno::EINVAL) ||
-            err == Error::Sys(Errno::ENOSYS));
+    assert!(err == Errno::EPERM || err == Errno::EINVAL ||
+            err == Errno::ENOSYS);
 }
 
 // Just make sure ptrace_setoptions can be called at all, for now.
@@ -26,7 +25,7 @@
 fn test_ptrace_setoptions() {
     require_capability!(CAP_SYS_PTRACE);
     let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD).unwrap_err();
-    assert!(err != Error::UnsupportedOperation);
+    assert!(err != Errno::EOPNOTSUPP);
 }
 
 // Just make sure ptrace_getevent can be called at all, for now.
@@ -35,7 +34,7 @@
 fn test_ptrace_getevent() {
     require_capability!(CAP_SYS_PTRACE);
     let err = ptrace::getevent(getpid()).unwrap_err();
-    assert!(err != Error::UnsupportedOperation);
+    assert!(err != Errno::EOPNOTSUPP);
 }
 
 // Just make sure ptrace_getsiginfo can be called at all, for now.
@@ -43,8 +42,8 @@
 #[cfg(any(target_os = "android", target_os = "linux"))]
 fn test_ptrace_getsiginfo() {
     require_capability!(CAP_SYS_PTRACE);
-    if let Err(Error::UnsupportedOperation) = ptrace::getsiginfo(getpid()) {
-        panic!("ptrace_getsiginfo returns Error::UnsupportedOperation!");
+    if let Err(Errno::EOPNOTSUPP) = ptrace::getsiginfo(getpid()) {
+        panic!("ptrace_getsiginfo returns Errno::EOPNOTSUPP!");
     }
 }
 
@@ -54,8 +53,8 @@
 fn test_ptrace_setsiginfo() {
     require_capability!(CAP_SYS_PTRACE);
     let siginfo = unsafe { mem::zeroed() };
-    if let Err(Error::UnsupportedOperation) = ptrace::setsiginfo(getpid(), &siginfo) {
-        panic!("ptrace_setsiginfo returns Error::UnsupportedOperation!");
+    if let Err(Errno::EOPNOTSUPP) = ptrace::setsiginfo(getpid(), &siginfo) {
+        panic!("ptrace_setsiginfo returns Errno::EOPNOTSUPP!");
     }
 }
 
@@ -79,7 +78,7 @@
     // On valid platforms the ptrace call should return Errno::EPERM, this
     // is already tested by `test_ptrace`.
     let err = ptrace::attach(getpid()).unwrap_err();
-    if err == Error::Sys(Errno::ENOSYS) {
+    if err == Errno::ENOSYS {
         return;
     }
 
diff --git a/test/sys/test_signal.rs b/test/sys/test_signal.rs
index c8c13e5..1b89af5 100644
--- a/test/sys/test_signal.rs
+++ b/test/sys/test_signal.rs
@@ -1,5 +1,5 @@
 #[cfg(not(target_os = "redox"))]
-use nix::Error;
+use nix::errno::Errno;
 use nix::sys::signal::*;
 use nix::unistd::*;
 use std::convert::TryFrom;
@@ -92,7 +92,7 @@
     let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
 
     let action_handler = SigHandler::SigAction(test_sigaction_action);
-    assert_eq!(unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(), Error::UnsupportedOperation);
+    assert_eq!(unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(), Errno::ENOTSUP);
 }
 
 #[test]
diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs
index c22eaeb..5471afe 100644
--- a/test/sys/test_socket.rs
+++ b/test/sys/test_socket.rs
@@ -519,7 +519,6 @@
 // Test error handling of our recvmsg wrapper
 #[test]
 pub fn test_recvmsg_ebadf() {
-    use nix::Error;
     use nix::errno::Errno;
     use nix::sys::socket::{MsgFlags, recvmsg};
     use nix::sys::uio::IoVec;
@@ -528,7 +527,7 @@
     let iov = [IoVec::from_mut_slice(&mut buf[..])];
     let fd = -1;    // Bad file descriptor
     let r = recvmsg(fd, &iov, None, MsgFlags::empty());
-    assert_eq!(r.err().unwrap(), Error::Sys(Errno::EBADF));
+    assert_eq!(r.err().unwrap(), Errno::EBADF);
 }
 
 // Disable the test on emulated platforms due to a bug in QEMU versions <
@@ -818,7 +817,6 @@
         target_os = "freebsd"))]
 #[test]
 pub fn test_sendmsg_ipv6packetinfo() {
-    use nix::Error;
     use nix::errno::Errno;
     use nix::sys::uio::IoVec;
     use nix::sys::socket::{socket, sendmsg, bind,
@@ -835,7 +833,7 @@
     let inet_addr = InetAddr::from_std(&std_sa);
     let sock_addr = SockAddr::new_inet(inet_addr);
 
-    if let Err(Error::Sys(Errno::EADDRNOTAVAIL)) = bind(sock, &sock_addr) {
+    if let Err(Errno::EADDRNOTAVAIL) = bind(sock, &sock_addr) {
         println!("IPv6 not available, skipping test.");
         return;
     }
@@ -1145,7 +1143,6 @@
 #[cfg(any(target_os = "macos", target_os = "ios"))]
 #[test]
 pub fn test_syscontrol() {
-    use nix::Error;
     use nix::errno::Errno;
     use nix::sys::socket::{socket, SockAddr, SockType, SockFlag, SockProtocol};
 
@@ -1153,7 +1150,7 @@
                     SockFlag::empty(), SockProtocol::KextControl)
              .expect("socket failed");
     let _sockaddr = SockAddr::new_sys_control(fd, "com.apple.net.utun_control", 0).expect("resolving sys_control name failed");
-    assert_eq!(SockAddr::new_sys_control(fd, "foo.bar.lol", 0).err(), Some(Error::Sys(Errno::ENOENT)));
+    assert_eq!(SockAddr::new_sys_control(fd, "foo.bar.lol", 0).err(), Some(Errno::ENOENT));
 
     // requires root privileges
     // connect(fd, &sockaddr).expect("connect failed");
@@ -1500,7 +1497,6 @@
 #[test]
 pub fn test_vsock() {
     use libc;
-    use nix::Error;
     use nix::errno::Errno;
     use nix::sys::socket::{AddressFamily, socket, bind, connect, listen,
                            SockAddr, SockType, SockFlag};
@@ -1516,7 +1512,7 @@
     // VMADDR_CID_HYPERVISOR is reserved, so we expect an EADDRNOTAVAIL error.
     let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_HYPERVISOR, port);
     assert_eq!(bind(s1, &sockaddr).err(),
-               Some(Error::Sys(Errno::EADDRNOTAVAIL)));
+               Some(Errno::EADDRNOTAVAIL));
 
     let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_ANY, port);
     assert_eq!(bind(s1, &sockaddr), Ok(()));
@@ -1649,3 +1645,86 @@
     // Close socket
     nix::unistd::close(in_socket).unwrap();
 }
+
+// Disable the test on emulated platforms because it fails in Cirrus-CI.  Lack of QEMU
+// support is suspected.
+#[cfg_attr(not(any(target_arch = "x86_64")), ignore)]
+#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
+#[test]
+fn test_recvmsg_rxq_ovfl() {
+    use nix::Error;
+    use nix::sys::socket::*;
+    use nix::sys::uio::IoVec;
+    use nix::sys::socket::sockopt::{RxqOvfl, RcvBuf};
+
+    let message = [0u8; 2048];
+    let bufsize = message.len() * 2;
+
+    let in_socket = socket(
+        AddressFamily::Inet,
+        SockType::Datagram,
+        SockFlag::empty(),
+        None).unwrap();
+    let out_socket = socket(
+        AddressFamily::Inet,
+        SockType::Datagram,
+        SockFlag::empty(),
+        None).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();
+    connect(out_socket, &address).unwrap();
+
+    // Set SO_RXQ_OVFL flag.
+    setsockopt(in_socket, RxqOvfl, &1).unwrap();
+
+    // Set the receiver buffer size to hold only 2 messages.
+    setsockopt(in_socket, RcvBuf, &bufsize).unwrap();
+
+    let mut drop_counter = 0;
+
+    for _ in 0..2 {
+        let iov = [IoVec::from_slice(&message)];
+        let flags = MsgFlags::empty();
+
+        // Send the 3 messages (the receiver buffer can only hold 2 messages)
+        // to create an overflow.
+        for _ in 0..3 {
+            let l = sendmsg(out_socket, &iov, &[], flags, Some(&address)).unwrap();
+            assert_eq!(message.len(), l);
+        }
+
+        // Receive the message and check the drop counter if any.
+        loop {
+            let mut buffer = vec![0u8; message.len()];
+            let mut cmsgspace = nix::cmsg_space!(u32);
+
+            let iov = [IoVec::from_mut_slice(&mut buffer)];
+
+            match recvmsg(
+                in_socket,
+                &iov,
+                Some(&mut cmsgspace),
+                MsgFlags::MSG_DONTWAIT) {
+                Ok(r) => {
+                    drop_counter = match r.cmsgs().next() {
+                        Some(ControlMessageOwned::RxqOvfl(drop_counter)) => drop_counter,
+                        Some(_) => panic!("Unexpected control message"),
+                        None => 0,
+                    };
+                },
+                Err(Error::EAGAIN) => { break; },
+                _ => { panic!("unknown recvmsg() error"); },
+            }
+        }
+    }
+
+    // One packet lost.
+    assert_eq!(drop_counter, 1);
+
+    // Close sockets
+    nix::unistd::close(in_socket).unwrap();
+    nix::unistd::close(out_socket).unwrap();
+}
diff --git a/test/sys/test_termios.rs b/test/sys/test_termios.rs
index 00aeb2f..63d6a51 100644
--- a/test/sys/test_termios.rs
+++ b/test/sys/test_termios.rs
@@ -1,7 +1,7 @@
 use std::os::unix::prelude::*;
 use tempfile::tempfile;
 
-use nix::{Error, fcntl};
+use nix::fcntl;
 use nix::errno::Errno;
 use nix::pty::openpty;
 use nix::sys::termios::{self, LocalFlags, OutputFlags, tcgetattr};
@@ -32,14 +32,14 @@
 fn test_tcgetattr_enotty() {
     let file = tempfile().unwrap();
     assert_eq!(termios::tcgetattr(file.as_raw_fd()).err(),
-               Some(Error::Sys(Errno::ENOTTY)));
+               Some(Errno::ENOTTY));
 }
 
 // Test tcgetattr on an invalid file descriptor
 #[test]
 fn test_tcgetattr_ebadf() {
     assert_eq!(termios::tcgetattr(-1).err(),
-               Some(Error::Sys(Errno::EBADF)));
+               Some(Errno::EBADF));
 }
 
 // Test modifying output flags
@@ -126,5 +126,5 @@
     let read = read(pty.master, &mut buf).unwrap_err();
     close(pty.master).unwrap();
     close(pty.slave).unwrap();
-    assert_eq!(read, Error::Sys(Errno::EAGAIN));
+    assert_eq!(read, Errno::EAGAIN);
 }
diff --git a/test/sys/test_wait.rs b/test/sys/test_wait.rs
index f68b8b0..2d26fb8 100644
--- a/test/sys/test_wait.rs
+++ b/test/sys/test_wait.rs
@@ -1,4 +1,4 @@
-use nix::Error;
+use nix::errno::Errno;
 use nix::unistd::*;
 use nix::unistd::ForkResult::*;
 use nix::sys::signal::*;
@@ -41,7 +41,7 @@
     let pid = Pid::from_raw(1);
     assert_eq!(WaitStatus::from_raw(pid, 0x0002), Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false)));
     assert_eq!(WaitStatus::from_raw(pid, 0x0200), Ok(WaitStatus::Exited(pid, 2)));
-    assert_eq!(WaitStatus::from_raw(pid, 0x7f7f), Err(Error::invalid_argument()));
+    assert_eq!(WaitStatus::from_raw(pid, 0x7f7f), Err(Errno::EINVAL));
 }
 
 #[test]
diff --git a/test/test.rs b/test/test.rs
index 5a5330b..94f8e22 100644
--- a/test/test.rs
+++ b/test/test.rs
@@ -13,6 +13,8 @@
 #[cfg(any(target_os = "android",
           target_os = "linux"))]
 mod test_kmod;
+#[cfg(target_os = "freebsd")]
+mod test_nmount;
 #[cfg(any(target_os = "dragonfly",
           target_os = "freebsd",
           target_os = "fushsia",
diff --git a/test/test_dir.rs b/test/test_dir.rs
index 4d7f5f7..0dc7308 100644
--- a/test/test_dir.rs
+++ b/test/test_dir.rs
@@ -51,5 +51,5 @@
 
 #[test]
 fn ebadf() {
-    assert_eq!(Dir::from_fd(-1).unwrap_err(), nix::Error::Sys(nix::errno::Errno::EBADF));
+    assert_eq!(Dir::from_fd(-1).unwrap_err(), nix::Error::EBADF);
 }
diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs
index 48d4662..ae6756e 100644
--- a/test/test_fcntl.rs
+++ b/test/test_fcntl.rs
@@ -1,11 +1,20 @@
 #[cfg(not(target_os = "redox"))]
-use nix::Error;
-#[cfg(not(target_os = "redox"))]
 use nix::errno::*;
 #[cfg(not(target_os = "redox"))]
 use nix::fcntl::{open, OFlag, readlink};
 #[cfg(not(target_os = "redox"))]
 use nix::fcntl::{openat, readlinkat, renameat};
+#[cfg(all(
+    target_os = "linux",
+    target_env = "gnu",
+    any(
+        target_arch = "x86_64",
+        target_arch = "x32",
+        target_arch = "powerpc",
+        target_arch = "s390x"
+    )
+))]
+use nix::fcntl::{RenameFlags, renameat2};
 #[cfg(not(target_os = "redox"))]
 use nix::sys::stat::Mode;
 #[cfg(not(target_os = "redox"))]
@@ -55,13 +64,139 @@
     let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
     renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap();
     assert_eq!(renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap_err(),
-               Error::Sys(Errno::ENOENT));
+               Errno::ENOENT);
     close(old_dirfd).unwrap();
     close(new_dirfd).unwrap();
     assert!(new_dir.path().join("new").exists());
 }
 
 #[test]
+#[cfg(all(
+    target_os = "linux",
+    target_env = "gnu",
+    any(
+        target_arch = "x86_64",
+        target_arch = "x32",
+        target_arch = "powerpc",
+        target_arch = "s390x"
+    )
+))]
+fn test_renameat2_behaves_like_renameat_with_no_flags() {
+    let old_dir = tempfile::tempdir().unwrap();
+    let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
+    let old_path = old_dir.path().join("old");
+    File::create(&old_path).unwrap();
+    let new_dir = tempfile::tempdir().unwrap();
+    let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
+    renameat2(
+        Some(old_dirfd),
+        "old",
+        Some(new_dirfd),
+        "new",
+        RenameFlags::empty(),
+    )
+    .unwrap();
+    assert_eq!(
+        renameat2(
+            Some(old_dirfd),
+            "old",
+            Some(new_dirfd),
+            "new",
+            RenameFlags::empty()
+        )
+        .unwrap_err(),
+        Errno::ENOENT
+    );
+    close(old_dirfd).unwrap();
+    close(new_dirfd).unwrap();
+    assert!(new_dir.path().join("new").exists());
+}
+
+#[test]
+#[cfg(all(
+    target_os = "linux",
+    target_env = "gnu",
+    any(
+        target_arch = "x86_64",
+        target_arch = "x32",
+        target_arch = "powerpc",
+        target_arch = "s390x"
+    )
+))]
+fn test_renameat2_exchange() {
+    let old_dir = tempfile::tempdir().unwrap();
+    let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
+    let old_path = old_dir.path().join("old");
+    {
+        let mut old_f = File::create(&old_path).unwrap();
+        old_f.write(b"old").unwrap();
+    }
+    let new_dir = tempfile::tempdir().unwrap();
+    let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
+    let new_path = new_dir.path().join("new");
+    {
+        let mut new_f = File::create(&new_path).unwrap();
+        new_f.write(b"new").unwrap();
+    }
+    renameat2(
+        Some(old_dirfd),
+        "old",
+        Some(new_dirfd),
+        "new",
+        RenameFlags::RENAME_EXCHANGE,
+    )
+    .unwrap();
+    let mut buf = String::new();
+    let mut new_f = File::open(&new_path).unwrap();
+    new_f.read_to_string(&mut buf).unwrap();
+    assert_eq!(buf, "old");
+    buf = "".to_string();
+    let mut old_f = File::open(&old_path).unwrap();
+    old_f.read_to_string(&mut buf).unwrap();
+    assert_eq!(buf, "new");
+    close(old_dirfd).unwrap();
+    close(new_dirfd).unwrap();
+}
+
+#[test]
+#[cfg(all(
+    target_os = "linux",
+    target_env = "gnu",
+    any(
+        target_arch = "x86_64",
+        target_arch = "x32",
+        target_arch = "powerpc",
+        target_arch = "s390x"
+    )
+))]
+fn test_renameat2_noreplace() {
+    let old_dir = tempfile::tempdir().unwrap();
+    let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
+    let old_path = old_dir.path().join("old");
+    File::create(&old_path).unwrap();
+    let new_dir = tempfile::tempdir().unwrap();
+    let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
+    let new_path = new_dir.path().join("new");
+    File::create(&new_path).unwrap();
+    assert_eq!(
+        renameat2(
+            Some(old_dirfd),
+            "old",
+            Some(new_dirfd),
+            "new",
+            RenameFlags::RENAME_NOREPLACE
+        )
+        .unwrap_err(),
+        Errno::EEXIST
+    );
+    close(old_dirfd).unwrap();
+    close(new_dirfd).unwrap();
+    assert!(new_dir.path().join("new").exists());
+    assert!(old_dir.path().join("old").exists());
+}
+
+
+#[test]
 #[cfg(not(target_os = "redox"))]
 fn test_readlink() {
     let tempdir = tempfile::tempdir().unwrap();
@@ -102,11 +237,15 @@
     /// resulting file is read and should contain the contents `bar`.
     /// The from_offset should be updated by the call to reflect
     /// the 3 bytes read (6).
-    ///
-    /// FIXME: This test is disabled for linux based builds, because Travis
-    /// Linux version is too old for `copy_file_range`.
     #[test]
-    #[ignore]
+    // QEMU does not support copy_file_range. Skip platforms that use QEMU in CI
+    #[cfg_attr(all(target_os = "linux", any(
+            target_arch = "aarch64",
+            target_arch = "arm",
+            target_arch = "mips",
+            target_arch = "mips64",
+            target_arch = "powerpc64"
+    )), ignore)]
     fn test_copy_file_range() {
         const CONTENTS: &[u8] = b"foobarbaz";
 
@@ -381,7 +520,7 @@
                 assert_eq!(tmp.read(&mut data).expect("read failure"), LEN);
                 assert_eq!(&data[..], &[0u8; LEN][..]);
             }
-            Err(nix::Error::Sys(Errno::EINVAL)) => {
+            Err(Errno::EINVAL) => {
                 // POSIX requires posix_fallocate to return EINVAL both for
                 // invalid arguments (i.e. len < 0) and if the operation is not
                 // supported by the file system.
@@ -397,12 +536,8 @@
     fn errno() {
         let (rd, _wr) = pipe().unwrap();
         let err = posix_fallocate(rd as RawFd, 0, 100).unwrap_err();
-        use nix::Error::Sys;
         match err {
-            Sys(Errno::EINVAL)
-                | Sys(Errno::ENODEV)
-                | Sys(Errno::ESPIPE)
-                | Sys(Errno::EBADF) => (),
+            Errno::EINVAL | Errno::ENODEV | Errno::ESPIPE | Errno::EBADF => (),
             errno =>
                 panic!(
                     "unexpected errno {}",
diff --git a/test/test_kmod/mod.rs b/test/test_kmod/mod.rs
index fb7260b..7626330 100644
--- a/test/test_kmod/mod.rs
+++ b/test/test_kmod/mod.rs
@@ -130,7 +130,7 @@
     let f = File::open(kmod_path).expect("unable to open kernel module");
     let result = finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty());
 
-    assert_eq!(result.unwrap_err(), Error::Sys(Errno::EINVAL));
+    assert_eq!(result.unwrap_err(), Error::from(Errno::EINVAL));
 }
 
 #[test]
@@ -147,7 +147,7 @@
 
     let result = finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty());
 
-    assert_eq!(result.unwrap_err(), Error::Sys(Errno::EEXIST));
+    assert_eq!(result.unwrap_err(), Error::from(Errno::EEXIST));
 
     delete_module(
         &CString::new(kmod_name).unwrap(),
@@ -163,5 +163,5 @@
 
     let result = delete_module(&CString::new("hello").unwrap(), DeleteModuleFlags::empty());
 
-    assert_eq!(result.unwrap_err(), Error::Sys(Errno::ENOENT));
+    assert_eq!(result.unwrap_err(), Error::from(Errno::ENOENT));
 }
diff --git a/test/test_mq.rs b/test/test_mq.rs
index 1667a35..d082692 100644
--- a/test/test_mq.rs
+++ b/test/test_mq.rs
@@ -1,8 +1,7 @@
 use std::ffi::CString;
 use std::str;
 
-use nix::errno::Errno::*;
-use nix::Error::Sys;
+use nix::errno::Errno;
 use nix::mqueue::{mq_open, mq_close, mq_send, mq_receive, mq_attr_member_t};
 use nix::mqueue::{MqAttr, MQ_OFlag};
 use nix::sys::stat::Mode;
@@ -16,7 +15,7 @@
     let oflag0 = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
     let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
     let r0 = mq_open(mq_name, oflag0, mode, Some(&attr));
-    if let Err(Sys(ENOSYS)) = r0 {
+    if let Err(Errno::ENOSYS) = r0 {
         println!("message queues not supported or module not loaded?");
         return;
     };
@@ -47,7 +46,7 @@
     let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
     let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
     let r = mq_open(mq_name, oflag, mode, Some(&initial_attr));
-    if let Err(Sys(ENOSYS)) = r {
+    if let Err(Errno::ENOSYS) = r {
         println!("message queues not supported or module not loaded?");
         return;
     };
@@ -70,7 +69,7 @@
     let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
     let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
     let r = mq_open(mq_name, oflag, mode, Some(&initial_attr));
-    if let Err(Sys(ENOSYS)) = r {
+    if let Err(Errno::ENOSYS) = r {
         println!("message queues not supported or module not loaded?");
         return;
     };
@@ -107,7 +106,7 @@
     let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
     let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
     let r = mq_open(mq_name, oflag, mode, Some(&initial_attr));
-    if let Err(Sys(ENOSYS)) = r {
+    if let Err(Errno::ENOSYS) = r {
         println!("message queues not supported or module not loaded?");
         return;
     };
@@ -132,7 +131,7 @@
     let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
     let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
     let r = mq_open(mq_name_opened, oflag, mode, Some(&initial_attr));
-    if let Err(Sys(ENOSYS)) = r {
+    if let Err(Errno::ENOSYS) = r {
         println!("message queues not supported or module not loaded?");
         return;
     };
@@ -142,9 +141,9 @@
     assert_eq!(res_unlink, Ok(()) );
 
     let res_unlink_not_opened = mq_unlink(mq_name_not_opened);
-    assert_eq!(res_unlink_not_opened, Err(Sys(ENOENT)) );
+    assert_eq!(res_unlink_not_opened, Err(Errno::ENOENT) );
 
     mq_close(mqd).unwrap();
     let res_unlink_after_close = mq_unlink(mq_name_opened);
-    assert_eq!(res_unlink_after_close, Err(Sys(ENOENT)) );
+    assert_eq!(res_unlink_after_close, Err(Errno::ENOENT) );
 }
diff --git a/test/test_nmount.rs b/test/test_nmount.rs
new file mode 100644
index 0000000..4c74ecf
--- /dev/null
+++ b/test/test_nmount.rs
@@ -0,0 +1,51 @@
+use crate::*;
+use nix::{
+    errno::Errno,
+    mount::{MntFlags, Nmount, unmount}
+};
+use std::{
+    ffi::CString,
+    fs::File,
+    path::Path
+};
+use tempfile::tempdir;
+
+#[test]
+fn ok() {
+    require_mount!("nullfs");
+
+    let mountpoint = tempdir().unwrap();
+    let target = tempdir().unwrap();
+    let _sentry = File::create(target.path().join("sentry")).unwrap();
+
+    let fstype = CString::new("fstype").unwrap();
+    let nullfs = CString::new("nullfs").unwrap();
+    Nmount::new()
+        .str_opt(&fstype, &nullfs)
+        .str_opt_owned("fspath", mountpoint.path().to_str().unwrap())
+        .str_opt_owned("target", target.path().to_str().unwrap())
+        .nmount(MntFlags::empty()).unwrap();
+    
+    // Now check that the sentry is visible through the mountpoint
+    let exists = Path::exists(&mountpoint.path().join("sentry"));
+
+    // Cleanup the mountpoint before asserting
+    unmount(mountpoint.path(), MntFlags::empty()).unwrap();
+    
+    assert!(exists);
+}
+
+#[test]
+fn bad_fstype() {
+    let mountpoint = tempdir().unwrap();
+    let target = tempdir().unwrap();
+    let _sentry = File::create(target.path().join("sentry")).unwrap();
+
+    let e = Nmount::new()
+        .str_opt_owned("fspath", mountpoint.path().to_str().unwrap())
+        .str_opt_owned("target", target.path().to_str().unwrap())
+        .nmount(MntFlags::empty()).unwrap_err();
+    
+    assert_eq!(e.error(), Errno::EINVAL);
+    assert_eq!(e.errmsg(), Some("Invalid fstype"));
+}
diff --git a/test/test_poll.rs b/test/test_poll.rs
index acfaad8..0395512 100644
--- a/test/test_poll.rs
+++ b/test/test_poll.rs
@@ -1,5 +1,4 @@
 use nix::{
-    Error,
     errno::Errno,
     poll::{PollFlags, poll, PollFd},
     unistd::{write, pipe}
@@ -10,7 +9,7 @@
         loop {
             match $poll_expr {
                 Ok(nfds) => break nfds,
-                Err(Error::Sys(Errno::EINTR)) => (),
+                Err(Errno::EINTR) => (),
                 Err(e) => panic!("{}", e)
             }
         }
diff --git a/test/test_ptymaster_drop.rs b/test/test_ptymaster_drop.rs
index ff939b9..a68f81e 100644
--- a/test/test_ptymaster_drop.rs
+++ b/test/test_ptymaster_drop.rs
@@ -12,10 +12,6 @@
     /// race condition.
     #[test]
     #[should_panic(expected = "Closing an invalid file descriptor!")]
-    // In Travis on i686-unknown-linux-musl, this test gets SIGABRT.  I don't
-    // know why.  It doesn't happen on any other target, and it doesn't happen
-    // on my PC.
-    #[cfg_attr(all(target_env = "musl", target_arch = "x86"), ignore)]
     fn test_double_close() {
         let m = posix_openpt(OFlag::O_RDWR).unwrap();
         close(m.as_raw_fd()).unwrap();
diff --git a/test/test_stat.rs b/test/test_stat.rs
index 27fcee5..424371f 100644
--- a/test/test_stat.rs
+++ b/test/test_stat.rs
@@ -15,7 +15,7 @@
 use libc::mode_t;
 
 #[cfg(not(target_os = "redox"))]
-use nix::{fcntl, Error};
+use nix::fcntl;
 #[cfg(not(target_os = "redox"))]
 use nix::errno::Errno;
 #[cfg(not(target_os = "redox"))]
@@ -304,5 +304,5 @@
     let dirfd = fcntl::open(&tempdir.path().join(not_dir_filename), fcntl::OFlag::O_CREAT,
                             stat::Mode::empty()).unwrap();
     let result = mkdirat(dirfd, filename, Mode::S_IRWXU).unwrap_err();
-    assert_eq!(result, Error::Sys(Errno::ENOTDIR));
+    assert_eq!(result, Errno::ENOTDIR);
 }
diff --git a/test/test_unistd.rs b/test/test_unistd.rs
index 94d2d1b..b95f154 100644
--- a/test/test_unistd.rs
+++ b/test/test_unistd.rs
@@ -1,6 +1,6 @@
 #[cfg(not(target_os = "redox"))]
 use nix::fcntl::{self, open, readlink};
-use nix::fcntl::{fcntl, FcntlArg, FdFlag, OFlag};
+use nix::fcntl::OFlag;
 use nix::unistd::*;
 use nix::unistd::ForkResult::*;
 #[cfg(not(target_os = "redox"))]
@@ -10,17 +10,15 @@
 #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
 use nix::pty::{posix_openpt, grantpt, unlockpt, ptsname};
 use nix::errno::Errno;
-#[cfg(not(target_os = "redox"))]
-use nix::Error;
 use std::{env, iter};
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "fuchsia", target_os = "redox")))]
 use std::ffi::CString;
 #[cfg(not(target_os = "redox"))]
 use std::fs::DirBuilder;
 use std::fs::{self, File};
 use std::io::Write;
 use std::os::unix::prelude::*;
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "fuchsia", target_os = "redox")))]
 use std::path::Path;
 use tempfile::{tempdir, tempfile};
 use libc::{_exit, mode_t, off_t};
@@ -135,6 +133,8 @@
     target_os = "macos", target_os = "ios",
     target_os = "android", target_os = "redox")))]
 fn test_mkfifoat() {
+    use nix::fcntl;
+
     let tempdir = tempdir().unwrap();
     let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
     let mkfifoat_name = "mkfifoat_name";
@@ -258,7 +258,7 @@
     setgroups(&old_groups).unwrap();
 }
 
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "fuchsia", target_os = "redox")))]
 macro_rules! execve_test_factory(
     ($test_name:ident, $syscall:ident, $exe: expr $(, $pathname:expr, $flags:expr)*) => (
 
@@ -669,6 +669,8 @@
           target_os = "solaris"))]
 #[test]
 fn test_pipe2() {
+    use nix::fcntl::{fcntl, FcntlArg, FdFlag};
+
     let (fd0, fd1) = pipe2(OFlag::O_CLOEXEC).unwrap();
     let f0 = FdFlag::from_bits_truncate(fcntl(fd0, FcntlArg::F_GETFD).unwrap());
     assert!(f0.contains(FdFlag::FD_CLOEXEC));
@@ -968,7 +970,7 @@
 
     // Attempt unlink dir at relative path without proper flag
     let err_result = unlinkat(Some(dirfd), dirname, UnlinkatFlags::NoRemoveDir).unwrap_err();
-    assert!(err_result == Error::Sys(Errno::EISDIR) || err_result == Error::Sys(Errno::EPERM));
+    assert!(err_result == Errno::EISDIR || err_result == Errno::EPERM);
  }
 
 #[test]
@@ -1011,7 +1013,7 @@
 fn test_access_not_existing() {
     let tempdir = tempdir().unwrap();
     let dir = tempdir.path().join("does_not_exist.txt");
-    assert_eq!(access(&dir, AccessFlags::F_OK).err().unwrap().as_errno().unwrap(),
+    assert_eq!(access(&dir, AccessFlags::F_OK).err().unwrap(),
                Errno::ENOENT);
 }
 
@@ -1090,13 +1092,13 @@
 fn test_ttyname_not_pty() {
     let fd = File::open("/dev/zero").unwrap();
     assert!(fd.as_raw_fd() > 0);
-    assert_eq!(ttyname(fd.as_raw_fd()), Err(Error::Sys(Errno::ENOTTY)));
+    assert_eq!(ttyname(fd.as_raw_fd()), Err(Errno::ENOTTY));
 }
 
 #[test]
 #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
 fn test_ttyname_invalid_fd() {
-    assert_eq!(ttyname(-1), Err(Error::Sys(Errno::EBADF)));
+    assert_eq!(ttyname(-1), Err(Errno::EBADF));
 }
 
 #[test]