Upgrade rust/crates/nix to 0.20.0 am: 4727c11bc6 am: e0d64e1271 am: 720f2e28ef

Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/nix/+/1662521

Change-Id: I635207d53e1dd048b062b16060f45e42d47cbbf9
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 35cd54b..82a8727 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,5 @@
 {
   "git": {
-    "sha1": "c8e8deff0e26a05165e66db17732794c2cd67324"
+    "sha1": "4c7021787a174493bf1abb90a711d7464e6c80f6"
   }
 }
diff --git a/.cirrus.yml b/.cirrus.yml
deleted file mode 100644
index 3591c0e..0000000
--- a/.cirrus.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-freebsd_instance:
-  image: freebsd-11-4-release-amd64
-
-# Test FreeBSD in a full VM on cirrus-ci.com.  Test the i686 target too, in the
-# same VM.  The binary will be built in 32-bit mode, but will execute on a
-# 64-bit kernel and in a 64-bit environment.  Our tests don't execute any of
-# the system's binaries, so the environment shouldn't matter.
-task:
-  name: FreeBSD 11.4
-  cargo_cache:
-    folder: $CARGO_HOME/registry
-    fingerprint_script: cat Cargo.lock || echo ""
-  # Install Rust
-  setup_script:
-    - fetch https://sh.rustup.rs -o rustup.sh
-    - sh rustup.sh -y --profile=minimal --default-toolchain 1.36.0
-    - $HOME/.cargo/bin/rustup target add i686-unknown-freebsd
-  amd64_test_script:
-    - . $HOME/.cargo/env
-    - cargo test
-  i386_test_script:
-    - . $HOME/.cargo/env
-    - cargo test --target i686-unknown-freebsd
-  before_cache_script: rm -rf $CARGO_HOME/registry/index
diff --git a/Android.bp b/Android.bp
index affc10e..03f16a5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -23,7 +23,6 @@
 
 rust_library {
     name: "libnix",
-    // has rustc warnings
     host_supported: true,
     crate_name: "nix",
     srcs: ["src/lib.rs"],
@@ -41,5 +40,5 @@
 
 // dependent_library ["feature_list"]
 //   bitflags-1.2.1 "default"
-//   cfg-if-0.1.10
-//   libc-0.2.89 "default,extra_traits,std"
+//   cfg-if-1.0.0
+//   libc-0.2.92 "default,extra_traits,std"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e018ab2..1297ba7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,12 +3,49 @@
 All notable changes to this project will be documented in this file.
 This project adheres to [Semantic Versioning](http://semver.org/).
 
-## [Unreleased] - ReleaseDate
+## [0.20.0] - 20 February 2021
 ### Added
+
+- Added a `passwd` field to `Group` (#[1338](https://github.com/nix-rust/nix/pull/1338))
+- Added `mremap` (#[1306](https://github.com/nix-rust/nix/pull/1306))
+- Added `personality` (#[1331](https://github.com/nix-rust/nix/pull/1331))
+- Added limited Fuchsia support (#[1285](https://github.com/nix-rust/nix/pull/1285))
+- Added `getpeereid` (#[1342](https://github.com/nix-rust/nix/pull/1342))
+- Implemented `IntoIterator` for `Dir`
+  (#[1333](https://github.com/nix-rust/nix/pull/1333)).
+
 ### Changed
+
+- Minimum supported Rust version is now 1.40.0.
+  ([#1356](https://github.com/nix-rust/nix/pull/1356))
+- i686-apple-darwin has been demoted to Tier 2 support, because it's deprecated
+  by Xcode.
+  (#[1350](https://github.com/nix-rust/nix/pull/1350))
+- Fixed calling `recvfrom` on an `AddrFamily::Packet` socket
+  (#[1344](https://github.com/nix-rust/nix/pull/1344))
+
 ### Fixed
+- `TimerFd` now closes the underlying fd on drop.
+  ([#1381](https://github.com/nix-rust/nix/pull/1381))
+- Define `*_MAGIC` filesystem constants on Linux s390x
+  (#[1372](https://github.com/nix-rust/nix/pull/1372))
+- mqueue, sysinfo, timespec, statfs, test_ptrace_syscall() on x32
+  (#[1366](https://github.com/nix-rust/nix/pull/1366))
+
 ### Removed
 
+- `Dir`, `SignalFd`, and `PtyMaster` are no longer `Clone`.
+  (#[1382](https://github.com/nix-rust/nix/pull/1382))
+- Removed `SockLevel`, which hasn't been used for a few years
+  (#[1362](https://github.com/nix-rust/nix/pull/1362))
+- Removed both `Copy` and `Clone` from `TimerFd`.
+  ([#1381](https://github.com/nix-rust/nix/pull/1381))
+
+## [0.19.1] - 28 November 2020
+### Fixed
+- Fixed bugs in `recvmmsg`.
+  (#[1341](https://github.com/nix-rust/nix/pull/1341))
+
 ## [0.19.0] - 6 October 2020
 ### Added
 - Added Netlink protocol families to the `SockProtocol` enum
@@ -52,7 +89,7 @@
 - Derived `Ord`, `PartialOrd` for `unistd::Pid` (#[1189](https://github.com/nix-rust/nix/pull/1189))
 - Added `select::FdSet::fds` method to iterate over file descriptors in a set.
   ([#1207](https://github.com/nix-rust/nix/pull/1207))
-- Added support for UDP generic segmentation offload (GSO) and generic 
+- Added support for UDP generic segmentation offload (GSO) and generic
   receive offload (GRO) ([#1209](https://github.com/nix-rust/nix/pull/1209))
 - Added support for `sendmmsg` and `recvmmsg` calls
   (#[1208](https://github.com/nix-rust/nix/pull/1208))
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 03a1f63..55990c4 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -76,21 +76,21 @@
 
 After you've made your change, make sure the tests pass in your development
 environment. We also have [continuous integration set up on
-Travis-CI][travis-ci], which might find some issues on other platforms. The CI
+Cirrus-CI][cirrus-ci], which might find some issues on other platforms. The CI
 will run once you open a pull request.
 
 There is also infrastructure for running tests for other targets
 locally.  More information is available in the [CI Readme][ci-readme].
 
-[travis-ci]: https://travis-ci.org/nix-rust/nix
+[cirrus-ci]: https://cirrus-ci.com/github/nix-rust/nix
 [ci-readme]: ci/README.md
 
 ### Disabling a test in the CI environment
 
 Sometimes there are features that cannot be tested in the CI environment.
-To stop a test from running under CI, add `#[cfg_attr(travis, ignore)]`
-to it. Please include a comment describing the reason it shouldn't run
-under CI, and a link to an upstream issue if possible!
+To stop a test from running under CI, add `skip_if_cirrus!()` to it. Please
+describe the reason it shouldn't run under CI, and a link to an issue if
+possible!
 
 ## bors, the bot who merges all the PRs
 
diff --git a/Cargo.toml b/Cargo.toml
index 3f08692..0562246 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,13 +13,15 @@
 [package]
 edition = "2018"
 name = "nix"
-version = "0.19.0"
+version = "0.20.0"
 authors = ["The nix-rust Project Developers"]
-exclude = ["/.gitignore", "/.travis.yml", "/ci/*", "/Cross.toml", "/RELEASE_PROCEDURE.md", "/bors.toml"]
+exclude = ["/.gitignore", "/.cirrus.yml", "/ci/*", "/Cross.toml", "/RELEASE_PROCEDURE.md", "/bors.toml"]
 description = "Rust friendly bindings to *nix APIs"
 categories = ["os::unix-apis"]
 license = "MIT"
 repository = "https://github.com/nix-rust/nix"
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu", "aarch64-linux-android", "x86_64-apple-darwin", "aarch64-apple-ios", "x86_64-unknown-freebsd", "x86_64-unknown-openbsd", "x86_64-unknown-netbsd", "x86_64-unknown-dragonfly", "x86_64-fuchsia", "x86_64-unknown-redox"]
 
 [[test]]
 name = "test"
@@ -49,10 +51,10 @@
 version = "1.1"
 
 [dependencies.cfg-if]
-version = "0.1.10"
+version = "1.0"
 
 [dependencies.libc]
-version = "0.2.78"
+version = "0.2.82"
 features = ["extra_traits"]
 [dev-dependencies.bytes]
 version = "0.4.8"
@@ -69,7 +71,7 @@
 [dev-dependencies.tempfile]
 version = "3.0.5"
 [target."cfg(any(target_os = \"android\", target_os = \"linux\"))".dev-dependencies.caps]
-version = "0.3.1"
+version = "0.5.1"
 [target."cfg(target_os = \"dragonfly\")".build-dependencies.cc]
 version = "1"
 [target."cfg(target_os = \"freebsd\")".dev-dependencies.sysctl]
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 31c3d71..885fa10 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -2,24 +2,38 @@
 name        = "nix"
 description = "Rust friendly bindings to *nix APIs"
 edition     = "2018"
-version     = "0.19.0"
+version     = "0.20.0"
 authors     = ["The nix-rust Project Developers"]
 repository  = "https://github.com/nix-rust/nix"
 license     = "MIT"
 categories  = ["os::unix-apis"]
 exclude     = [
   "/.gitignore",
-  "/.travis.yml",
+  "/.cirrus.yml",
   "/ci/*",
   "/Cross.toml",
   "/RELEASE_PROCEDURE.md",
   "/bors.toml"
 ]
 
+[package.metadata.docs.rs]
+targets = [
+  "x86_64-unknown-linux-gnu",
+  "aarch64-linux-android",
+  "x86_64-apple-darwin",
+  "aarch64-apple-ios",
+  "x86_64-unknown-freebsd",
+  "x86_64-unknown-openbsd",
+  "x86_64-unknown-netbsd",
+  "x86_64-unknown-dragonfly",
+  "x86_64-fuchsia",
+  "x86_64-unknown-redox"
+]
+
 [dependencies]
-libc = { version = "0.2.78", features = [ "extra_traits" ] }
+libc = { version = "0.2.82", features = [ "extra_traits" ] }
 bitflags = "1.1"
-cfg-if = "0.1.10"
+cfg-if = "1.0"
 
 [target.'cfg(target_os = "dragonfly")'.build-dependencies]
 cc = "1"
@@ -32,7 +46,7 @@
 semver = "0.9.0"
 
 [target.'cfg(any(target_os = "android", target_os = "linux"))'.dev-dependencies]
-caps = "0.3.1"
+caps = "0.5.1"
 
 [target.'cfg(target_os = "freebsd")'.dev-dependencies]
 sysctl = "0.1"
diff --git a/METADATA b/METADATA
index d8c25cb..a71ef07 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://static.crates.io/crates/nix/nix-0.19.0.crate"
+    value: "https://static.crates.io/crates/nix/nix-0.20.0.crate"
   }
-  version: "0.19.0"
+  version: "0.20.0"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2020
-    month: 10
-    day: 13
+    year: 2021
+    month: 4
+    day: 2
   }
 }
diff --git a/README.md b/README.md
index 43c47e1..167d192 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,5 @@
 # Rust bindings to *nix APIs
 
-[![Travis Build Status](https://travis-ci.org/nix-rust/nix.svg?branch=master)](https://travis-ci.org/nix-rust/nix)
 [![Cirrus Build Status](https://api.cirrus-ci.com/github/nix-rust/nix.svg)](https://cirrus-ci.com/github/nix-rust/nix)
 [![crates.io](http://meritbadge.herokuapp.com/nix)](https://crates.io/crates/nix)
 
@@ -51,7 +50,6 @@
   * aarch64-unknown-linux-gnu
   * arm-unknown-linux-gnueabi
   * armv7-unknown-linux-gnueabihf
-  * i686-apple-darwin
   * i686-unknown-freebsd
   * i686-unknown-linux-gnu
   * i686-unknown-linux-musl
@@ -74,6 +72,7 @@
   * armv7-linux-androideabi
   * armv7s-apple-ios
   * i386-apple-ios
+  * i686-apple-darwin
   * i686-linux-android
   * powerpc-unknown-linux-gnu
   * s390x-unknown-linux-gnu
@@ -82,17 +81,19 @@
   * x86_64-unknown-netbsd
 
 Tier 3:
+  * x86_64-fuchsia
   * x86_64-unknown-redox
+  * x86_64-unknown-linux-gnux32
 
 ## Usage
 
-`nix` requires Rust 1.36.0 or newer.
+`nix` requires Rust 1.40.0 or newer.
 
 To use `nix`, add this to your `Cargo.toml`:
 
 ```toml
 [dependencies]
-nix = "0.19.0"
+nix = "0.20.0"
 ```
 
 ## Contributing
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 7397f01..5d7fef5 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -2,13 +2,13 @@
 {
   "presubmit": [
     {
+      "name": "keystore2_test"
+    },
+    {
       "name": "keystore2_crypto_test_rust"
     },
     {
       "name": "vpnprofilestore_test"
-    },
-    {
-      "name": "keystore2_test"
     }
   ]
 }
diff --git a/src/dir.rs b/src/dir.rs
index 1d48f18..7d4ab82 100644
--- a/src/dir.rs
+++ b/src/dir.rs
@@ -25,7 +25,7 @@
 ///    * returns entries for `.` (current directory) and `..` (parent directory).
 ///    * returns entries' names as a `CStr` (no allocation or conversion beyond whatever libc
 ///      does).
-#[derive(Clone, Debug, Eq, Hash, PartialEq)]
+#[derive(Debug, Eq, Hash, PartialEq)]
 pub struct Dir(
     ptr::NonNull<libc::DIR>
 );
@@ -85,7 +85,32 @@
 
 impl Drop for Dir {
     fn drop(&mut self) {
-        unsafe { libc::closedir(self.0.as_ptr()) };
+        let e = Errno::result(unsafe { libc::closedir(self.0.as_ptr()) });
+        if !std::thread::panicking() && e == Err(Error::Sys(Errno::EBADF)) {
+            panic!("Closing an invalid file descriptor!");
+        };
+    }
+}
+
+fn next(dir: &mut Dir) -> Option<Result<Entry>> {
+    unsafe {
+        // Note: POSIX specifies that portable applications should dynamically allocate a
+        // buffer with room for a `d_name` field of size `pathconf(..., _PC_NAME_MAX)` plus 1
+        // for the NUL byte. It doesn't look like the std library does this; it just uses
+        // fixed-sized buffers (and libc's dirent seems to be sized so this is appropriate).
+        // Probably fine here too then.
+        let mut ent = std::mem::MaybeUninit::<dirent>::uninit();
+        let mut result = ptr::null_mut();
+        if let Err(e) = Errno::result(
+            readdir_r(dir.0.as_ptr(), ent.as_mut_ptr(), &mut result))
+        {
+            return Some(Err(e));
+        }
+        if result.is_null() {
+            return None;
+        }
+        assert_eq!(result, ent.as_mut_ptr());
+        Some(Ok(Entry(ent.assume_init())))
     }
 }
 
@@ -96,25 +121,7 @@
     type Item = Result<Entry>;
 
     fn next(&mut self) -> Option<Self::Item> {
-        unsafe {
-            // Note: POSIX specifies that portable applications should dynamically allocate a
-            // buffer with room for a `d_name` field of size `pathconf(..., _PC_NAME_MAX)` plus 1
-            // for the NUL byte. It doesn't look like the std library does this; it just uses
-            // fixed-sized buffers (and libc's dirent seems to be sized so this is appropriate).
-            // Probably fine here too then.
-            let mut ent = std::mem::MaybeUninit::<dirent>::uninit();
-            let mut result = ptr::null_mut();
-            if let Err(e) = Errno::result(
-                readdir_r((self.0).0.as_ptr(), ent.as_mut_ptr(), &mut result))
-            {
-                return Some(Err(e));
-            }
-            if result.is_null() {
-                return None;
-            }
-            assert_eq!(result, ent.as_mut_ptr());
-            Some(Ok(Entry(ent.assume_init())))
-        }
+        next(self.0)
     }
 }
 
@@ -124,6 +131,43 @@
     }
 }
 
+/// The return type of [Dir::into_iter]
+#[derive(Debug, Eq, Hash, PartialEq)]
+pub struct OwningIter(Dir);
+
+impl Iterator for OwningIter {
+    type Item = Result<Entry>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        next(&mut self.0)
+    }
+}
+
+impl IntoIterator for Dir {
+    type Item = Result<Entry>;
+    type IntoIter = OwningIter;
+
+    /// Creates a owning iterator, that is, one that takes ownership of the
+    /// `Dir`. The `Dir` cannot be used after calling this.  This can be useful
+    /// when you have a function that both creates a `Dir` instance and returns
+    /// an `Iterator`.
+    ///
+    /// Example:
+    ///
+    /// ```
+    /// use nix::{dir::Dir, fcntl::OFlag, sys::stat::Mode};
+    /// use std::{iter::Iterator, string::String};
+    ///
+    /// fn ls_upper(dirname: &str) -> impl Iterator<Item=String> {
+    ///     let d = Dir::open(dirname, OFlag::O_DIRECTORY, Mode::S_IXUSR).unwrap();
+    ///     d.into_iter().map(|x| x.unwrap().file_name().as_ref().to_string_lossy().to_ascii_uppercase())
+    /// }
+    /// ```
+    fn into_iter(self) -> Self::IntoIter {
+        OwningIter(self)
+    }
+}
+
 /// A directory entry, similar to `std::fs::DirEntry`.
 ///
 /// Note that unlike the std version, this may represent the `.` or `..` entries.
diff --git a/src/errno.rs b/src/errno.rs
index 03a7f0e..e5c7092 100644
--- a/src/errno.rs
+++ b/src/errno.rs
@@ -20,7 +20,8 @@
         }
     } else if #[cfg(any(target_os = "linux",
                         target_os = "redox",
-                        target_os = "dragonfly"))] {
+                        target_os = "dragonfly",
+                        target_os = "fuchsia"))] {
         unsafe fn errno_location() -> *mut c_int {
             libc::__errno_location()
         }
@@ -188,192 +189,254 @@
         EHOSTDOWN       => "Host is down",
         EHOSTUNREACH    => "No route to host",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ECHRNG          => "Channel number out of range",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EL2NSYNC        => "Level 2 not synchronized",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EL3HLT          => "Level 3 halted",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EL3RST          => "Level 3 reset",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ELNRNG          => "Link number out of range",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EUNATCH         => "Protocol driver not attached",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ENOCSI          => "No CSI structure available",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EL2HLT          => "Level 2 halted",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EBADE           => "Invalid exchange",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EBADR           => "Invalid request descriptor",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EXFULL          => "Exchange full",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ENOANO          => "No anode",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EBADRQC         => "Invalid request code",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EBADSLT         => "Invalid slot",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EBFONT          => "Bad font file format",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ENOSTR          => "Device not a stream",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ENODATA         => "No data available",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ETIME           => "Timer expired",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ENOSR           => "Out of streams resources",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ENONET          => "Machine is not on the network",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ENOPKG          => "Package not installed",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EREMOTE         => "Object is remote",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ENOLINK         => "Link has been severed",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EADV            => "Advertise error",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ESRMNT          => "Srmount error",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ECOMM           => "Communication error on send",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EPROTO          => "Protocol error",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EMULTIHOP       => "Multihop attempted",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EDOTDOT         => "RFS specific error",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EBADMSG         => "Not a data message",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EOVERFLOW       => "Value too large for defined data type",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ENOTUNIQ        => "Name not unique on network",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EBADFD          => "File descriptor in bad state",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EREMCHG         => "Remote address changed",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ELIBACC         => "Can not access a needed shared library",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ELIBBAD         => "Accessing a corrupted shared library",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ELIBSCN         => ".lib section in a.out corrupted",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ELIBMAX         => "Attempting to link in too many shared libraries",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ELIBEXEC        => "Cannot exec a shared library directly",
 
-        #[cfg(any(target_os = "linux", target_os = "android", target_os = "openbsd"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia", target_os = "openbsd"))]
         EILSEQ          => "Illegal byte sequence",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ERESTART        => "Interrupted system call should be restarted",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ESTRPIPE        => "Streams pipe error",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EUSERS          => "Too many users",
 
         #[cfg(any(target_os = "linux", target_os = "android",
-                  target_os = "netbsd", target_os = "redox"))]
+                  target_os = "fuchsia", target_os = "netbsd",
+                  target_os = "redox"))]
         EOPNOTSUPP      => "Operation not supported on transport endpoint",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ESTALE          => "Stale file handle",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EUCLEAN         => "Structure needs cleaning",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ENOTNAM         => "Not a XENIX named type file",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ENAVAIL         => "No XENIX semaphores available",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EISNAM          => "Is a named type file",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EREMOTEIO       => "Remote I/O error",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EDQUOT          => "Quota exceeded",
 
         #[cfg(any(target_os = "linux", target_os = "android",
-                  target_os = "openbsd", target_os = "dragonfly"))]
+                  target_os = "fuchsia", target_os = "openbsd",
+                  target_os = "dragonfly"))]
         ENOMEDIUM       => "No medium found",
 
-        #[cfg(any(target_os = "linux", target_os = "android", target_os = "openbsd"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia", target_os = "openbsd"))]
         EMEDIUMTYPE     => "Wrong medium type",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ECANCELED       => "Operation canceled",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ENOKEY          => "Required key not available",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EKEYEXPIRED     => "Key has expired",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EKEYREVOKED     => "Key has been revoked",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EKEYREJECTED    => "Key was rejected by service",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         EOWNERDEAD      => "Owner died",
 
-        #[cfg(any(target_os = "linux", target_os = "android"))]
+        #[cfg(any(target_os = "linux", target_os = "android",
+                  target_os = "fuchsia"))]
         ENOTRECOVERABLE => "State not recoverable",
 
-        #[cfg(all(target_os = "linux", not(target_arch="mips")))]
+        #[cfg(any(all(target_os = "linux", not(target_arch="mips")),
+                  target_os = "fuchsia"))]
         ERFKILL         => "Operation not possible due to RF-kill",
 
-        #[cfg(all(target_os = "linux", not(target_arch="mips")))]
+        #[cfg(any(all(target_os = "linux", not(target_arch="mips")),
+                  target_os = "fuchsia"))]
         EHWPOISON       => "Memory page has hardware error",
 
         #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
@@ -567,7 +630,8 @@
     }
 }
 
-#[cfg(any(target_os = "linux", target_os = "android"))]
+#[cfg(any(target_os = "linux", target_os = "android",
+          target_os = "fuchsia"))]
 mod consts {
     #[derive(Clone, Copy, Debug, Eq, PartialEq)]
     #[repr(i32)]
diff --git a/src/fcntl.rs b/src/fcntl.rs
index 1581d3a..d2242da 100644
--- a/src/fcntl.rs
+++ b/src/fcntl.rs
@@ -20,7 +20,7 @@
     target_os = "fuchsia",
     any(target_os = "wasi", target_env = "wasi"),
     target_env = "uclibc",
-    target_env = "freebsd"
+    target_os = "freebsd"
 ))]
 pub use self::posix_fadvise::*;
 
@@ -587,7 +587,7 @@
     target_os = "fuchsia",
     any(target_os = "wasi", target_env = "wasi"),
     target_env = "uclibc",
-    target_env = "freebsd"
+    target_os = "freebsd"
 ))]
 mod posix_fadvise {
     use crate::errno::Errno;
diff --git a/src/features.rs b/src/features.rs
index c3a53fb..6b1cff5 100644
--- a/src/features.rs
+++ b/src/features.rs
@@ -97,7 +97,7 @@
 #[cfg(any(target_os = "macos", target_os = "freebsd",
           target_os = "dragonfly", target_os = "ios",
           target_os = "openbsd", target_os = "netbsd",
-          target_os = "redox"))]
+          target_os = "redox", target_os = "fuchsia"))]
 mod os {
     /// Check if the OS supports atomic close-on-exec for sockets
     pub fn socket_atomic_cloexec() -> bool {
diff --git a/src/lib.rs b/src/lib.rs
index da517b5..e62c158 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -57,7 +57,7 @@
 #[deny(missing_docs)]
 pub mod poll;
 #[deny(missing_docs)]
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
 pub mod pty;
 pub mod sched;
 pub mod sys;
diff --git a/src/mqueue.rs b/src/mqueue.rs
index 122705a..0215de5 100644
--- a/src/mqueue.rs
+++ b/src/mqueue.rs
@@ -5,7 +5,7 @@
 use crate::Result;
 use crate::errno::Errno;
 
-use libc::{self, c_char, c_long, mqd_t, size_t};
+use libc::{self, c_char, mqd_t, size_t};
 use std::ffi::CString;
 use crate::sys::stat::Mode;
 use std::mem;
@@ -34,11 +34,18 @@
     mq_attr: libc::mq_attr,
 }
 
+// x32 compatibility
+// See https://sourceware.org/bugzilla/show_bug.cgi?id=21279
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
+pub type mq_attr_member_t = i64;
+#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
+pub type mq_attr_member_t = libc::c_long;
+
 impl MqAttr {
-    pub fn new(mq_flags: c_long,
-               mq_maxmsg: c_long,
-               mq_msgsize: c_long,
-               mq_curmsgs: c_long)
+    pub fn new(mq_flags: mq_attr_member_t,
+               mq_maxmsg: mq_attr_member_t,
+               mq_msgsize: mq_attr_member_t,
+               mq_curmsgs: mq_attr_member_t)
                -> MqAttr
     {
         let mut attr = mem::MaybeUninit::<libc::mq_attr>::uninit();
@@ -52,7 +59,7 @@
         }
     }
 
-    pub fn flags(&self) -> c_long {
+    pub fn flags(&self) -> mq_attr_member_t {
         self.mq_attr.mq_flags
     }
 }
@@ -150,7 +157,7 @@
 /// Returns the old attributes
 pub fn mq_set_nonblock(mqd: mqd_t) -> Result<MqAttr> {
     let oldattr = mq_getattr(mqd)?;
-    let newattr = MqAttr::new(c_long::from(MQ_OFlag::O_NONBLOCK.bits()),
+    let newattr = MqAttr::new(mq_attr_member_t::from(MQ_OFlag::O_NONBLOCK.bits()),
                               oldattr.mq_attr.mq_maxmsg,
                               oldattr.mq_attr.mq_msgsize,
                               oldattr.mq_attr.mq_curmsgs);
diff --git a/src/pty.rs b/src/pty.rs
index 3a6a923..d67518f 100644
--- a/src/pty.rs
+++ b/src/pty.rs
@@ -43,7 +43,7 @@
 /// While this datatype is a thin wrapper around `RawFd`, it enforces that the available PTY
 /// functions are given the correct file descriptor. Additionally this type implements `Drop`,
 /// so that when it's consumed or goes out of scope, it's automatically cleaned-up.
-#[derive(Clone, Debug, Eq, Hash, PartialEq)]
+#[derive(Debug, Eq, Hash, PartialEq)]
 pub struct PtyMaster(RawFd);
 
 impl AsRawFd for PtyMaster {
diff --git a/src/sys/mman.rs b/src/sys/mman.rs
index b2bed6e..63a0779 100644
--- a/src/sys/mman.rs
+++ b/src/sys/mman.rs
@@ -139,6 +139,17 @@
     }
 }
 
+#[cfg(target_os = "linux")]
+libc_bitflags!{
+    /// Options for `mremap()`.
+    pub struct MRemapFlags: c_int {
+        /// Permit the kernel to relocate the mapping to a new virtual address, if necessary.
+        MREMAP_MAYMOVE;
+        /// Place the mapping at exactly the address specified in `new_address`.
+        MREMAP_FIXED;
+    }
+}
+
 libc_enum!{
     /// Usage information for a range of memory to allow for performance optimizations by the kernel.
     ///
@@ -315,6 +326,30 @@
     }
 }
 
+/// Expands (or shrinks) an existing memory mapping, potentially moving it at
+/// the same time.
+///
+/// # Safety
+///
+/// See the `mremap(2)` [man page](https://man7.org/linux/man-pages/man2/mremap.2.html) for
+/// detailed requirements.
+#[cfg(target_os = "linux")]
+pub unsafe fn mremap(
+    addr: *mut c_void,
+    old_size: size_t,
+    new_size: size_t,
+    flags: MRemapFlags,
+    new_address: Option<* mut c_void>,
+) -> Result<*mut c_void> {
+    let ret = libc::mremap(addr, old_size, new_size, flags.bits(), new_address.unwrap_or(std::ptr::null_mut()));
+
+    if ret == libc::MAP_FAILED {
+        Err(Error::Sys(Errno::last()))
+    } else {
+        Ok(ret)
+    }
+}
+
 /// remove a mapping
 ///
 /// # Safety
diff --git a/src/sys/mod.rs b/src/sys/mod.rs
index b8b9e6f..02edfd7 100644
--- a/src/sys/mod.rs
+++ b/src/sys/mod.rs
@@ -38,6 +38,9 @@
 #[cfg(not(target_os = "redox"))]
 pub mod mman;
 
+#[cfg(target_os = "linux")]
+pub mod personality;
+
 pub mod pthread;
 
 #[cfg(any(target_os = "android",
diff --git a/src/sys/personality.rs b/src/sys/personality.rs
new file mode 100644
index 0000000..6548b65
--- /dev/null
+++ b/src/sys/personality.rs
@@ -0,0 +1,70 @@
+use crate::Result;
+use crate::errno::Errno;
+
+use libc::{self, c_int, c_ulong};
+
+libc_bitflags! {
+    /// Flags used and returned by [`get()`](fn.get.html) and
+    /// [`set()`](fn.set.html).
+    pub struct Persona: c_int {
+        ADDR_COMPAT_LAYOUT;
+        ADDR_NO_RANDOMIZE;
+        ADDR_LIMIT_32BIT;
+        ADDR_LIMIT_3GB;
+        #[cfg(not(target_env = "musl"))]
+        FDPIC_FUNCPTRS;
+        MMAP_PAGE_ZERO;
+        READ_IMPLIES_EXEC;
+        SHORT_INODE;
+        STICKY_TIMEOUTS;
+        #[cfg(not(target_env = "musl"))]
+        UNAME26;
+        WHOLE_SECONDS;
+    }
+}
+
+/// Retrieve the current process personality.
+///
+/// Returns a Result containing a Persona instance.
+///
+/// Example:
+///
+/// ```
+/// # use nix::sys::personality::{self, Persona};
+/// let pers = personality::get().unwrap();
+/// assert!(!pers.contains(Persona::WHOLE_SECONDS));
+/// ```
+pub fn get() -> Result<Persona> {
+    let res = unsafe {
+        libc::personality(0xFFFFFFFF)
+    };
+
+    Errno::result(res).map(|r| Persona::from_bits_truncate(r))
+}
+
+/// Set the current process personality.
+///
+/// Returns a Result containing the *previous* personality for the
+/// process, as a Persona.
+///
+/// For more information, see [personality(2)](https://man7.org/linux/man-pages/man2/personality.2.html)
+///
+/// **NOTE**: This call **replaces** the current personality entirely.
+/// To **update** the personality, first call `get()` and then `set()`
+/// with the modified persona.
+///
+/// Example:
+///
+/// ```
+/// # use nix::sys::personality::{self, Persona};
+/// let mut pers = personality::get().unwrap();
+/// assert!(!pers.contains(Persona::ADDR_NO_RANDOMIZE));
+/// personality::set(pers | Persona::ADDR_NO_RANDOMIZE);
+/// ```
+pub fn set(persona: Persona) -> Result<Persona> {
+    let res = unsafe {
+        libc::personality(persona.bits() as c_ulong)
+    };
+
+    Errno::result(res).map(|r| Persona::from_bits_truncate(r))
+}
diff --git a/src/sys/signal.rs b/src/sys/signal.rs
index 710e65f..2f8b5fa 100644
--- a/src/sys/signal.rs
+++ b/src/sys/signal.rs
@@ -39,8 +39,10 @@
         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"))))]
+        #[cfg(all(any(target_os = "android", target_os = "emscripten",
+                      target_os = "fuchsia", target_os = "linux"),
+                  not(any(target_arch = "mips", target_arch = "mips64",
+                          target_arch = "sparc64"))))]
         SIGSTKFLT,
         SIGCHLD,
         SIGCONT,
@@ -55,14 +57,17 @@
         SIGPROF,
         SIGWINCH,
         SIGIO,
-        #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
+        #[cfg(any(target_os = "android", target_os = "emscripten",
+                  target_os = "fuchsia", target_os = "linux"))]
         SIGPWR,
         SIGSYS,
         #[cfg(not(any(target_os = "android", target_os = "emscripten",
-                      target_os = "linux", target_os = "redox")))]
+                      target_os = "fuchsia", target_os = "linux",
+                      target_os = "redox")))]
         SIGEMT,
         #[cfg(not(any(target_os = "android", target_os = "emscripten",
-                      target_os = "linux", target_os = "redox")))]
+                      target_os = "fuchsia", target_os = "linux",
+                      target_os = "redox")))]
         SIGINFO,
     }
 }
@@ -86,8 +91,10 @@
             "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"))))]
+            #[cfg(all(any(target_os = "android", target_os = "emscripten",
+                          target_os = "fuchsia", target_os = "linux"),
+                      not(any(target_arch = "mips", target_arch = "mips64",
+                              target_arch = "sparc64"))))]
             "SIGSTKFLT" => Signal::SIGSTKFLT,
             "SIGCHLD" => Signal::SIGCHLD,
             "SIGCONT" => Signal::SIGCONT,
@@ -102,14 +109,17 @@
             "SIGPROF" => Signal::SIGPROF,
             "SIGWINCH" => Signal::SIGWINCH,
             "SIGIO" => Signal::SIGIO,
-            #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
+            #[cfg(any(target_os = "android", target_os = "emscripten",
+                      target_os = "fuchsia", target_os = "linux"))]
             "SIGPWR" => Signal::SIGPWR,
             "SIGSYS" => Signal::SIGSYS,
             #[cfg(not(any(target_os = "android", target_os = "emscripten",
-                          target_os = "linux", target_os = "redox")))]
+                          target_os = "fuchsia", target_os = "linux",
+                          target_os = "redox")))]
             "SIGEMT" => Signal::SIGEMT,
             #[cfg(not(any(target_os = "android", target_os = "emscripten",
-                          target_os = "linux", target_os = "redox")))]
+                          target_os = "fuchsia", target_os = "linux",
+                          target_os = "redox")))]
             "SIGINFO" => Signal::SIGINFO,
             _ => return Err(Error::invalid_argument()),
         })
@@ -139,7 +149,8 @@
             Signal::SIGPIPE => "SIGPIPE",
             Signal::SIGALRM => "SIGALRM",
             Signal::SIGTERM => "SIGTERM",
-            #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
+            #[cfg(all(any(target_os = "android", target_os = "emscripten",
+                          target_os = "fuchsia", target_os = "linux"),
                       not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
             Signal::SIGSTKFLT => "SIGSTKFLT",
             Signal::SIGCHLD => "SIGCHLD",
@@ -155,14 +166,17 @@
             Signal::SIGPROF => "SIGPROF",
             Signal::SIGWINCH => "SIGWINCH",
             Signal::SIGIO => "SIGIO",
-            #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
+            #[cfg(any(target_os = "android", target_os = "emscripten",
+                      target_os = "fuchsia", target_os = "linux"))]
             Signal::SIGPWR => "SIGPWR",
             Signal::SIGSYS => "SIGSYS",
             #[cfg(not(any(target_os = "android", target_os = "emscripten",
-                          target_os = "linux", target_os = "redox")))]
+                          target_os = "fuchsia", target_os = "linux",
+                          target_os = "redox")))]
             Signal::SIGEMT => "SIGEMT",
             #[cfg(not(any(target_os = "android", target_os = "emscripten",
-                          target_os = "linux", target_os = "redox")))]
+                          target_os = "fuchsia", target_os = "linux",
+                          target_os = "redox")))]
             Signal::SIGINFO => "SIGINFO",
         }
     }
@@ -213,7 +227,10 @@
     SIGWINCH,
     SIGIO,
     SIGSYS];
-#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
+#[cfg(all(any(target_os = "linux", target_os = "android",
+              target_os = "emscripten", target_os = "fuchsia"),
+          not(any(target_arch = "mips", target_arch = "mips64",
+                  target_arch = "sparc64"))))]
 const SIGNALS: [Signal; 31] = [
     SIGHUP,
     SIGINT,
@@ -246,7 +263,10 @@
     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")))]
+#[cfg(all(any(target_os = "linux", target_os = "android",
+              target_os = "emscripten", target_os = "fuchsia"),
+          any(target_arch = "mips", target_arch = "mips64",
+              target_arch = "sparc64")))]
 const SIGNALS: [Signal; 30] = [
     SIGHUP,
     SIGINT,
@@ -279,7 +299,8 @@
     SIGPWR,
     SIGSYS];
 #[cfg(not(any(target_os = "linux", target_os = "android",
-              target_os = "emscripten", target_os = "redox")))]
+              target_os = "fuchsia", target_os = "emscripten",
+              target_os = "redox")))]
 const SIGNALS: [Signal; 31] = [
     SIGHUP,
     SIGINT,
@@ -749,6 +770,7 @@
 /// If `pgrp` less then or equal 1, the behavior is platform-specific.
 /// If `signal` is `None`, `killpg` will only preform error checking and won't
 /// send any signal.
+#[cfg(not(target_os = "fuchsia"))]
 pub fn killpg<T: Into<Option<Signal>>>(pgrp: Pid, signal: T) -> Result<()> {
     let res = unsafe { libc::killpg(pgrp.into(),
                                   match signal.into() {
@@ -829,7 +851,10 @@
         /// `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>()};
+            // NB: This uses MaybeUninit rather than mem::zeroed because libc::sigevent contains a
+            // function pointer on Fuchsia as of https://github.com/rust-lang/libc/commit/2f59370,
+            // and function pointers must not be null.
+            let mut sev = unsafe { mem::MaybeUninit::<libc::sigevent>::zeroed().assume_init() };
             sev.sigev_notify = match sigev_notify {
                 SigevNotify::SigevNone => libc::SIGEV_NONE,
                 SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL,
diff --git a/src/sys/signalfd.rs b/src/sys/signalfd.rs
index e3ded1f..c43b450 100644
--- a/src/sys/signalfd.rs
+++ b/src/sys/signalfd.rs
@@ -79,7 +79,7 @@
 ///     Err(err) => (), // some error happend
 /// }
 /// ```
-#[derive(Clone, Debug, Eq, Hash, PartialEq)]
+#[derive(Debug, Eq, Hash, PartialEq)]
 pub struct SignalFd(RawFd);
 
 impl SignalFd {
@@ -116,7 +116,10 @@
 
 impl Drop for SignalFd {
     fn drop(&mut self) {
-        let _ = unistd::close(self.0);
+        let e = unistd::close(self.0);
+        if !std::thread::panicking() && e == Err(Error::Sys(Errno::EBADF)) {
+            panic!("Closing an invalid file descriptor!");
+        };
     }
 }
 
diff --git a/src/sys/socket/addr.rs b/src/sys/socket/addr.rs
index 8784a37..2299c57 100644
--- a/src/sys/socket/addr.rs
+++ b/src/sys/socket/addr.rs
@@ -21,7 +21,8 @@
           target_os = "linux",
           target_os = "macos",
           target_os = "netbsd",
-          target_os = "openbsd"))]
+          target_os = "openbsd",
+          target_os = "fuchsia"))]
 pub use self::datalink::LinkAddr;
 #[cfg(any(target_os = "android", target_os = "linux"))]
 pub use self::vsock::VsockAddr;
@@ -41,7 +42,7 @@
     #[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"))]
+    #[cfg(any(target_os = "android", target_os = "linux", target_os = "fuchsia"))]
     Packet = libc::AF_PACKET,
     /// KEXT Controls and Notifications
     #[cfg(any(target_os = "ios", target_os = "macos"))]
@@ -718,6 +719,7 @@
     ///
     /// unsafe because it takes a raw pointer as argument.  The caller must
     /// ensure that the pointer is valid.
+    #[cfg(not(target_os = "fuchsia"))]
     pub(crate) unsafe fn from_libc_sockaddr(addr: *const libc::sockaddr) -> Option<SockAddr> {
         if addr.is_null() {
             None
@@ -1045,7 +1047,7 @@
 }
 
 
-#[cfg(any(target_os = "android", target_os = "linux"))]
+#[cfg(any(target_os = "android", target_os = "linux", target_os = "fuchsia"))]
 mod datalink {
     use super::{fmt, AddressFamily};
 
diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs
index 5e5fb8d..11ed329 100644
--- a/src/sys/socket/mod.rs
+++ b/src/sys/socket/mod.rs
@@ -847,12 +847,13 @@
             }
             #[cfg(any(target_os = "android", target_os = "linux"))]
             ControlMessage::AlgSetIv(iv) => {
+                #[allow(deprecated)] // https://github.com/rust-lang/libc/issues/1501
                 let af_alg_iv = libc::af_alg_iv {
                     ivlen: iv.len() as u32,
                     iv: [0u8; 0],
                 };
 
-                let size = mem::size_of::<libc::af_alg_iv>();
+                let size = mem::size_of_val(&af_alg_iv);
 
                 unsafe {
                     ptr::copy_nonoverlapping(
@@ -915,7 +916,7 @@
             }
             #[cfg(any(target_os = "android", target_os = "linux"))]
             ControlMessage::AlgSetIv(iv) => {
-                mem::size_of::<libc::af_alg_iv>() + iv.len()
+                mem::size_of_val(&iv) + iv.len()
             },
             #[cfg(any(target_os = "android", target_os = "linux"))]
             ControlMessage::AlgSetOp(op) => {
@@ -1216,17 +1217,18 @@
 
     let ret = unsafe { libc::recvmmsg(fd, output.as_mut_ptr(), output.len() as _, flags.bits() as _, timeout) };
 
-    let r = Errno::result(ret)?;
+    let _ = Errno::result(ret)?;
 
     Ok(output
         .into_iter()
+        .take(ret as usize)
         .zip(addresses.iter().map(|addr| unsafe{addr.assume_init()}))
         .zip(results.into_iter())
         .map(|((mmsghdr, address), (msg_controllen, cmsg_buffer))| {
             unsafe {
                 read_mhdr(
                     mmsghdr.msg_hdr,
-                    r as isize,
+                    mmsghdr.msg_len as isize,
                     msg_controllen,
                     address,
                     cmsg_buffer
@@ -1574,24 +1576,6 @@
  *
  */
 
-/// 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,
-    #[cfg(any(target_os = "android", target_os = "linux"))]
-    Alg = libc::SOL_ALG,
-}
-
 /// Represents a socket option that can be accessed or set. Used as an argument
 /// to `getsockopt`
 pub trait GetSockOpt : Copy {
@@ -1718,6 +1702,15 @@
             Ok(SockAddr::Unix(UnixAddr(sun, pathlen)))
         }
         #[cfg(any(target_os = "android", target_os = "linux"))]
+        libc::AF_PACKET => {
+            use libc::sockaddr_ll;
+            assert_eq!(len as usize, mem::size_of::<sockaddr_ll>());
+            let sll = unsafe {
+                *(addr as *const _ as *const sockaddr_ll)
+            };
+            Ok(SockAddr::Link(LinkAddr(sll)))
+        }
+        #[cfg(any(target_os = "android", target_os = "linux"))]
         libc::AF_NETLINK => {
             use libc::sockaddr_nl;
             let snl = unsafe {
diff --git a/src/sys/socket/sockopt.rs b/src/sys/socket/sockopt.rs
index e41a472..5b7b4fe 100644
--- a/src/sys/socket/sockopt.rs
+++ b/src/sys/socket/sockopt.rs
@@ -252,7 +252,9 @@
           target_os = "linux",
           target_os = "nacl"))]
 sockopt_impl!(Both, TcpKeepIdle, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32);
+#[cfg(not(target_os = "openbsd"))]
 sockopt_impl!(Both, TcpKeepCount, libc::IPPROTO_TCP, libc::TCP_KEEPCNT, u32);
+#[cfg(not(target_os = "openbsd"))]
 sockopt_impl!(Both, TcpKeepInterval, libc::IPPROTO_TCP, libc::TCP_KEEPINTVL, u32);
 sockopt_impl!(Both, RcvBuf, libc::SOL_SOCKET, libc::SO_RCVBUF, usize);
 sockopt_impl!(Both, SndBuf, libc::SOL_SOCKET, libc::SO_SNDBUF, usize);
diff --git a/src/sys/statfs.rs b/src/sys/statfs.rs
index 8e90a58..27b7259 100644
--- a/src/sys/statfs.rs
+++ b/src/sys/statfs.rs
@@ -16,79 +16,85 @@
 pub struct Statfs(libc::statfs);
 
 #[cfg(target_os = "freebsd")]
-#[derive(Eq, Copy, Clone, PartialEq, Debug)]
-pub struct FsType(pub u32);
+type fs_type_t = u32;
 #[cfg(target_os = "android")]
-#[derive(Eq, Copy, Clone, PartialEq, Debug)]
-pub struct FsType(pub libc::c_ulong);
+type fs_type_t = libc::c_ulong;
 #[cfg(all(target_os = "linux", target_arch = "s390x"))]
-#[derive(Eq, Copy, Clone, PartialEq, Debug)]
-pub struct FsType(pub u32);
+type fs_type_t = libc::c_uint;
 #[cfg(all(target_os = "linux", target_env = "musl"))]
-#[derive(Eq, Copy, Clone, PartialEq, Debug)]
-pub struct FsType(pub libc::c_ulong);
+type fs_type_t = libc::c_ulong;
 #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
-#[derive(Eq, Copy, Clone, PartialEq, Debug)]
-pub struct FsType(pub libc::c_long);
+type fs_type_t = libc::__fsword_t;
 
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const ADFS_SUPER_MAGIC: FsType = FsType(libc::ADFS_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const AFFS_SUPER_MAGIC: FsType = FsType(libc::AFFS_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const CODA_SUPER_MAGIC: FsType = FsType(libc::CODA_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const CRAMFS_MAGIC: FsType = FsType(libc::CRAMFS_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const EFS_SUPER_MAGIC: FsType = FsType(libc::EFS_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const EXT2_SUPER_MAGIC: FsType = FsType(libc::EXT2_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const EXT3_SUPER_MAGIC: FsType = FsType(libc::EXT3_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const EXT4_SUPER_MAGIC: FsType = FsType(libc::EXT4_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const HPFS_SUPER_MAGIC: FsType = FsType(libc::HPFS_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const HUGETLBFS_MAGIC: FsType = FsType(libc::HUGETLBFS_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const ISOFS_SUPER_MAGIC: FsType = FsType(libc::ISOFS_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const JFFS2_SUPER_MAGIC: FsType = FsType(libc::JFFS2_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const MINIX_SUPER_MAGIC: FsType = FsType(libc::MINIX_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const MINIX_SUPER_MAGIC2: FsType = FsType(libc::MINIX_SUPER_MAGIC2);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const MINIX2_SUPER_MAGIC: FsType = FsType(libc::MINIX2_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const MINIX2_SUPER_MAGIC2: FsType = FsType(libc::MINIX2_SUPER_MAGIC2);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const MSDOS_SUPER_MAGIC: FsType = FsType(libc::MSDOS_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const NCP_SUPER_MAGIC: FsType = FsType(libc::NCP_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const NFS_SUPER_MAGIC: FsType = FsType(libc::NFS_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const OPENPROM_SUPER_MAGIC: FsType = FsType(libc::OPENPROM_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const OVERLAYFS_SUPER_MAGIC: FsType = FsType(libc::OVERLAYFS_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const PROC_SUPER_MAGIC: FsType = FsType(libc::PROC_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const QNX4_SUPER_MAGIC: FsType = FsType(libc::QNX4_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const REISERFS_SUPER_MAGIC: FsType = FsType(libc::REISERFS_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const SMB_SUPER_MAGIC: FsType = FsType(libc::SMB_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const TMPFS_MAGIC: FsType = FsType(libc::TMPFS_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const USBDEVICE_SUPER_MAGIC: FsType = FsType(libc::USBDEVICE_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const CGROUP_SUPER_MAGIC: FsType = FsType(libc::CGROUP_SUPER_MAGIC);
-#[cfg(all(target_os = "linux", not(target_env = "musl"), not(target_arch = "s390x")))]
-pub const CGROUP2_SUPER_MAGIC: FsType = FsType(libc::CGROUP2_SUPER_MAGIC);
+#[cfg(any(
+    target_os = "freebsd",
+    target_os = "android",
+    all(target_os = "linux", target_arch = "s390x"),
+    all(target_os = "linux", target_env = "musl"),
+    all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))),
+))]
+#[derive(Eq, Copy, Clone, PartialEq, Debug)]
+pub struct FsType(pub fs_type_t);
+
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const ADFS_SUPER_MAGIC: FsType = FsType(libc::ADFS_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const AFFS_SUPER_MAGIC: FsType = FsType(libc::AFFS_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const CODA_SUPER_MAGIC: FsType = FsType(libc::CODA_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const CRAMFS_MAGIC: FsType = FsType(libc::CRAMFS_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const EFS_SUPER_MAGIC: FsType = FsType(libc::EFS_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const EXT2_SUPER_MAGIC: FsType = FsType(libc::EXT2_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const EXT3_SUPER_MAGIC: FsType = FsType(libc::EXT3_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const EXT4_SUPER_MAGIC: FsType = FsType(libc::EXT4_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const HPFS_SUPER_MAGIC: FsType = FsType(libc::HPFS_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const HUGETLBFS_MAGIC: FsType = FsType(libc::HUGETLBFS_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const ISOFS_SUPER_MAGIC: FsType = FsType(libc::ISOFS_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const JFFS2_SUPER_MAGIC: FsType = FsType(libc::JFFS2_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const MINIX_SUPER_MAGIC: FsType = FsType(libc::MINIX_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const MINIX_SUPER_MAGIC2: FsType = FsType(libc::MINIX_SUPER_MAGIC2 as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const MINIX2_SUPER_MAGIC: FsType = FsType(libc::MINIX2_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const MINIX2_SUPER_MAGIC2: FsType = FsType(libc::MINIX2_SUPER_MAGIC2 as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const MSDOS_SUPER_MAGIC: FsType = FsType(libc::MSDOS_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const NCP_SUPER_MAGIC: FsType = FsType(libc::NCP_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const NFS_SUPER_MAGIC: FsType = FsType(libc::NFS_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const OPENPROM_SUPER_MAGIC: FsType = FsType(libc::OPENPROM_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const OVERLAYFS_SUPER_MAGIC: FsType = FsType(libc::OVERLAYFS_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const PROC_SUPER_MAGIC: FsType = FsType(libc::PROC_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const QNX4_SUPER_MAGIC: FsType = FsType(libc::QNX4_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const REISERFS_SUPER_MAGIC: FsType = FsType(libc::REISERFS_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const SMB_SUPER_MAGIC: FsType = FsType(libc::SMB_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const TMPFS_MAGIC: FsType = FsType(libc::TMPFS_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const USBDEVICE_SUPER_MAGIC: FsType = FsType(libc::USBDEVICE_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const CGROUP_SUPER_MAGIC: FsType = FsType(libc::CGROUP_SUPER_MAGIC as fs_type_t);
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+pub const CGROUP2_SUPER_MAGIC: FsType = FsType(libc::CGROUP2_SUPER_MAGIC as fs_type_t);
+
 
 impl Statfs {
     /// Magic code defining system type
@@ -138,7 +144,7 @@
 
     /// Optimal transfer block size
     #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
-    pub fn optimal_transfer_size(&self) -> libc::c_long {
+    pub fn optimal_transfer_size(&self) -> libc::__fsword_t {
         self.0.f_bsize
     }
 
@@ -177,7 +183,7 @@
     /// Size of a block
     // f_bsize on linux: https://github.com/torvalds/linux/blob/master/fs/nfs/super.c#L471
     #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
-    pub fn block_size(&self) -> libc::c_long {
+    pub fn block_size(&self) -> libc::__fsword_t {
         self.0.f_bsize
     }
 
@@ -219,7 +225,7 @@
 
     /// Maximum length of filenames
     #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
-    pub fn maximum_name_length(&self) -> libc::c_long {
+    pub fn maximum_name_length(&self) -> libc::__fsword_t {
         self.0.f_namelen
     }
 
@@ -248,7 +254,7 @@
     }
 
     /// Total data blocks in filesystem
-    #[cfg(all(target_os = "linux", target_env = "musl"))]
+    #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
     pub fn blocks(&self) -> u64 {
         self.0.f_blocks
     }
@@ -261,7 +267,7 @@
         target_os = "freebsd",
         target_os = "openbsd",
         target_os = "dragonfly",
-        all(target_os = "linux", target_env = "musl")
+        all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32")))
     )))]
     pub fn blocks(&self) -> libc::c_ulong {
         self.0.f_blocks
@@ -286,7 +292,7 @@
     }
 
     /// Free blocks in filesystem
-    #[cfg(all(target_os = "linux", target_env = "musl"))]
+    #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
     pub fn blocks_free(&self) -> u64 {
         self.0.f_bfree
     }
@@ -299,7 +305,7 @@
         target_os = "freebsd",
         target_os = "openbsd",
         target_os = "dragonfly",
-        all(target_os = "linux", target_env = "musl")
+        all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32")))
     )))]
     pub fn blocks_free(&self) -> libc::c_ulong {
         self.0.f_bfree
@@ -324,7 +330,7 @@
     }
 
     /// Free blocks available to unprivileged user
-    #[cfg(all(target_os = "linux", target_env = "musl"))]
+    #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
     pub fn blocks_available(&self) -> u64 {
         self.0.f_bavail
     }
@@ -337,7 +343,7 @@
         target_os = "freebsd",
         target_os = "openbsd",
         target_os = "dragonfly",
-        all(target_os = "linux", target_env = "musl")
+        all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32")))
     )))]
     pub fn blocks_available(&self) -> libc::c_ulong {
         self.0.f_bavail
@@ -362,8 +368,8 @@
     }
 
     /// Total file nodes in filesystem
-    #[cfg(all(target_os = "linux", target_env = "musl"))]
-    pub fn files(&self) -> u64 {
+    #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
+    pub fn files(&self) -> libc::fsfilcnt_t {
         self.0.f_files
     }
 
@@ -375,7 +381,7 @@
         target_os = "freebsd",
         target_os = "openbsd",
         target_os = "dragonfly",
-        all(target_os = "linux", target_env = "musl")
+        all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32")))
     )))]
     pub fn files(&self) -> libc::c_ulong {
         self.0.f_files
@@ -385,7 +391,6 @@
     #[cfg(any(
             target_os = "android",
             target_os = "ios",
-            all(target_os = "linux", target_env = "musl"),
             target_os = "macos",
             target_os = "openbsd"
     ))]
@@ -406,6 +411,12 @@
     }
 
     /// Free file nodes in filesystem
+    #[cfg(all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32"))))]
+    pub fn files_free(&self) -> libc::fsfilcnt_t {
+        self.0.f_ffree
+    }
+
+    /// Free file nodes in filesystem
     #[cfg(not(any(
         target_os = "ios",
         target_os = "macos",
@@ -413,7 +424,7 @@
         target_os = "freebsd",
         target_os = "openbsd",
         target_os = "dragonfly",
-        all(target_os = "linux", target_env = "musl")
+        all(target_os = "linux", any(target_env = "musl", all(target_arch = "x86_64", target_pointer_width = "32")))
     )))]
     pub fn files_free(&self) -> libc::c_ulong {
         self.0.f_ffree
diff --git a/src/sys/sysinfo.rs b/src/sys/sysinfo.rs
index f4b8279..222a2fc 100644
--- a/src/sys/sysinfo.rs
+++ b/src/sys/sysinfo.rs
@@ -10,6 +10,12 @@
 #[repr(transparent)]
 pub struct SysInfo(libc::sysinfo);
 
+// The fields are c_ulong on 32-bit linux, u64 on 64-bit linux; x32's ulong is u32
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
+type mem_blocks_t = u64;
+#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
+type mem_blocks_t = libc::c_ulong;
+
 impl SysInfo {
     /// Returns the load average tuple.
     ///
@@ -58,7 +64,7 @@
         self.scale_mem(self.0.freeram)
     }
 
-    fn scale_mem(&self, units: libc::c_ulong) -> u64 {
+    fn scale_mem(&self, units: mem_blocks_t) -> u64 {
         units as u64 * self.0.mem_unit as u64
     }
 }
diff --git a/src/sys/time.rs b/src/sys/time.rs
index 269b425..7546d1b 100644
--- a/src/sys/time.rs
+++ b/src/sys/time.rs
@@ -1,7 +1,8 @@
 use std::{cmp, fmt, ops};
 use std::time::Duration;
 use std::convert::From;
-use libc::{c_long, timespec, timeval};
+use libc::{timespec, timeval};
+#[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
 pub use libc::{time_t, suseconds_t};
 
 pub trait TimeValLike: Sized {
@@ -61,6 +62,13 @@
 
 const TS_MIN_SECONDS: i64 = -TS_MAX_SECONDS;
 
+// x32 compatibility
+// See https://sourceware.org/bugzilla/show_bug.cgi?id=16437
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
+type timespec_tv_nsec_t = i64;
+#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
+type timespec_tv_nsec_t = libc::c_long;
+
 impl From<timespec> for TimeSpec {
     fn from(ts: timespec) -> Self {
         Self(ts)
@@ -69,9 +77,10 @@
 
 impl From<Duration> for TimeSpec {
     fn from(duration: Duration) -> Self {
+        #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
         TimeSpec(timespec {
             tv_sec: duration.as_secs() as time_t,
-            tv_nsec: duration.subsec_nanos() as c_long
+            tv_nsec: duration.subsec_nanos() as timespec_tv_nsec_t
         })
     }
 }
@@ -117,6 +126,7 @@
     fn seconds(seconds: i64) -> TimeSpec {
         assert!(seconds >= TS_MIN_SECONDS && seconds <= TS_MAX_SECONDS,
                 "TimeSpec out of bounds; seconds={}", seconds);
+        #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
         TimeSpec(timespec {tv_sec: seconds as time_t, tv_nsec: 0 })
     }
 
@@ -143,8 +153,9 @@
         let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC);
         assert!(secs >= TS_MIN_SECONDS && secs <= TS_MAX_SECONDS,
                 "TimeSpec out of bounds");
+        #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
         TimeSpec(timespec {tv_sec: secs as time_t,
-                           tv_nsec: nanos as c_long })
+                           tv_nsec: nanos as timespec_tv_nsec_t })
     }
 
     fn num_seconds(&self) -> i64 {
@@ -171,19 +182,20 @@
 }
 
 impl TimeSpec {
-    fn nanos_mod_sec(&self) -> c_long {
+    fn nanos_mod_sec(&self) -> timespec_tv_nsec_t {
         if self.tv_sec() < 0 && self.tv_nsec() > 0 {
-            self.tv_nsec() - NANOS_PER_SEC as c_long
+            self.tv_nsec() - NANOS_PER_SEC as timespec_tv_nsec_t
         } else {
             self.tv_nsec()
         }
     }
 
+    #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
     pub fn tv_sec(&self) -> time_t {
         self.0.tv_sec
     }
 
-    pub fn tv_nsec(&self) -> c_long {
+    pub fn tv_nsec(&self) -> timespec_tv_nsec_t {
         self.0.tv_nsec
     }
 }
@@ -315,6 +327,7 @@
     fn seconds(seconds: i64) -> TimeVal {
         assert!(seconds >= TV_MIN_SECONDS && seconds <= TV_MAX_SECONDS,
                 "TimeVal out of bounds; seconds={}", seconds);
+        #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
         TimeVal(timeval {tv_sec: seconds as time_t, tv_usec: 0 })
     }
 
@@ -332,6 +345,7 @@
         let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
         assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS,
                 "TimeVal out of bounds");
+        #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
         TimeVal(timeval {tv_sec: secs as time_t,
                            tv_usec: micros as suseconds_t })
     }
@@ -344,6 +358,7 @@
         let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
         assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS,
                 "TimeVal out of bounds");
+        #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
         TimeVal(timeval {tv_sec: secs as time_t,
                            tv_usec: micros as suseconds_t })
     }
@@ -380,6 +395,7 @@
         }
     }
 
+    #[cfg_attr(target_env = "musl", allow(deprecated))] // https://github.com/rust-lang/libc/issues/1848
     pub fn tv_sec(&self) -> time_t {
         self.0.tv_sec
     }
diff --git a/src/sys/timerfd.rs b/src/sys/timerfd.rs
index 3086309..4a24719 100644
--- a/src/sys/timerfd.rs
+++ b/src/sys/timerfd.rs
@@ -37,7 +37,7 @@
 
 /// A timerfd instance. This is also a file descriptor, you can feed it to
 /// other interfaces consuming file descriptors, epoll for example.
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug)]
 pub struct TimerFd {
     fd: RawFd,
 }
@@ -166,7 +166,7 @@
 impl TimerFd {
     /// Creates a new timer based on the clock defined by `clockid`. The
     /// underlying fd can be assigned specific flags with `flags` (CLOEXEC,
-    /// NONBLOCK).
+    /// NONBLOCK). The underlying fd will be closed on drop.
     pub fn new(clockid: ClockId, flags: TimerFlags) -> Result<Self> {
         Errno::result(unsafe { libc::timerfd_create(clockid as i32, flags.bits()) })
             .map(|fd| Self { fd })
@@ -270,3 +270,16 @@
         Ok(())
     }
 }
+
+impl Drop for TimerFd {
+    fn drop(&mut self) {
+        if !std::thread::panicking() {
+            let result = Errno::result(unsafe {
+                libc::close(self.fd)
+            });
+            if let Err(Error::Sys(Errno::EBADF)) = result {
+                panic!("close of TimerFd encountered EBADF");
+            }
+        }
+    }
+}
diff --git a/src/sys/wait.rs b/src/sys/wait.rs
index 0c04042..faf8543 100644
--- a/src/sys/wait.rs
+++ b/src/sys/wait.rs
@@ -1,9 +1,9 @@
+use crate::errno::Errno;
+use crate::sys::signal::Signal;
+use crate::unistd::Pid;
+use crate::Result;
 use cfg_if::cfg_if;
 use libc::{self, c_int};
-use crate::Result;
-use crate::errno::Errno;
-use crate::unistd::Pid;
-use crate::sys::signal::Signal;
 use std::convert::TryFrom;
 
 libc_bitflags!(
@@ -108,8 +108,7 @@
     pub fn pid(&self) -> Option<Pid> {
         use self::WaitStatus::*;
         match *self {
-            Exited(p, _)  | Signaled(p, _, _) |
-                Stopped(p, _) | Continued(p) => Some(p),
+            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),
@@ -117,49 +116,41 @@
     }
 }
 
-#[allow(unused_unsafe)]
 fn exited(status: i32) -> bool {
-    unsafe { libc::WIFEXITED(status) }
+    libc::WIFEXITED(status)
 }
 
-#[allow(unused_unsafe)]
 fn exit_status(status: i32) -> i32 {
-    unsafe { libc::WEXITSTATUS(status) }
+    libc::WEXITSTATUS(status)
 }
 
-#[allow(unused_unsafe)]
 fn signaled(status: i32) -> bool {
-    unsafe { libc::WIFSIGNALED(status) }
+    libc::WIFSIGNALED(status)
 }
 
-#[allow(unused_unsafe)]
 fn term_signal(status: i32) -> Result<Signal> {
-    Signal::try_from(unsafe { libc::WTERMSIG(status) })
+    Signal::try_from(libc::WTERMSIG(status))
 }
 
-#[allow(unused_unsafe)]
 fn dumped_core(status: i32) -> bool {
-    unsafe { libc::WCOREDUMP(status) }
+    libc::WCOREDUMP(status)
 }
 
-#[allow(unused_unsafe)]
 fn stopped(status: i32) -> bool {
-    unsafe { libc::WIFSTOPPED(status) }
+    libc::WIFSTOPPED(status)
 }
 
-#[allow(unused_unsafe)]
 fn stop_signal(status: i32) -> Result<Signal> {
-    Signal::try_from(unsafe { libc::WSTOPSIG(status) })
+    Signal::try_from(libc::WSTOPSIG(status))
 }
 
 #[cfg(any(target_os = "android", target_os = "linux"))]
-#[allow(unused_unsafe)]
 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 }
+    libc::WSTOPSIG(status) == libc::SIGTRAP | 0x80
 }
 
 #[cfg(any(target_os = "android", target_os = "linux"))]
@@ -167,9 +158,8 @@
     (status >> 16) as c_int
 }
 
-#[allow(unused_unsafe)]
 fn continued(status: i32) -> bool {
-    unsafe { libc::WIFCONTINUED(status) }
+    libc::WIFCONTINUED(status)
 }
 
 impl WaitStatus {
diff --git a/src/time.rs b/src/time.rs
index 54989c2..e6c3f8d 100644
--- a/src/time.rs
+++ b/src/time.rs
@@ -37,6 +37,7 @@
     }
 
     /// Returns resolution of the clock id
+    #[cfg(not(target_os = "redox"))]
     pub fn res(self) -> Result<TimeSpec> {
         clock_getres(self)
     }
@@ -204,6 +205,7 @@
 
 /// Get the resolution of the specified clock, (see
 /// [clock_getres(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_getres.html)).
+#[cfg(not(target_os = "redox"))]
 pub fn clock_getres(clock_id: ClockId) -> Result<TimeSpec> {
     let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
     let ret = unsafe { libc::clock_getres(clock_id.as_raw(), c_time.as_mut_ptr()) };
diff --git a/src/unistd.rs b/src/unistd.rs
index 04031e3..7a4517e 100644
--- a/src/unistd.rs
+++ b/src/unistd.rs
@@ -12,9 +12,9 @@
            uid_t, gid_t, mode_t, PATH_MAX};
 use std::{fmt, mem, ptr};
 use std::convert::Infallible;
-use std::ffi::{CStr, CString, OsString};
+use std::ffi::{CStr, OsString};
 #[cfg(not(target_os = "redox"))]
-use std::ffi::{OsStr};
+use std::ffi::{CString, OsStr};
 use std::os::unix::ffi::OsStringExt;
 #[cfg(not(target_os = "redox"))]
 use std::os::unix::ffi::OsStrExt;
@@ -426,6 +426,7 @@
 /// This function may fail in a number of different scenarios.  See the man
 /// pages for additional details on possible failure cases.
 #[inline]
+#[cfg(not(target_os = "fuchsia"))]
 pub fn fchdir(dirfd: RawFd) -> Result<()> {
     let res = unsafe { libc::fchdir(dirfd) };
 
@@ -1095,7 +1096,7 @@
 ///
 /// See also
 /// [truncate(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html)
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
 pub fn truncate<P: ?Sized + NixPath>(path: &P, len: off_t) -> Result<()> {
     let res = path.with_nix_path(|cstr| {
         unsafe {
@@ -1232,6 +1233,7 @@
 
 
 #[inline]
+#[cfg(not(target_os = "fuchsia"))]
 pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> {
     let res = path.with_nix_path(|cstr| {
         unsafe { libc::chroot(cstr.as_ptr()) }
@@ -1633,7 +1635,8 @@
     //!
     //! Scheduling an alarm and waiting for the signal:
     //!
-    //! ```
+#![cfg_attr(target_os = "redox", doc = " ```rust,ignore")]
+#![cfg_attr(not(target_os = "redox"), doc = " ```rust")]
     //! use std::time::{Duration, Instant};
     //!
     //! use nix::unistd::{alarm, pause};
@@ -1642,14 +1645,23 @@
     //! // We need to setup an empty signal handler to catch the alarm signal,
     //! // otherwise the program will be terminated once the signal is delivered.
     //! extern fn signal_handler(_: nix::libc::c_int) { }
-    //! unsafe { sigaction(Signal::SIGALRM, &SigAction::new(SigHandler::Handler(signal_handler), SaFlags::empty(), SigSet::empty())); }
+    //! let sa = SigAction::new(
+    //!     SigHandler::Handler(signal_handler),
+    //!     SaFlags::empty(),
+    //!     SigSet::empty()
+    //! );
+    //! unsafe {
+    //!     sigaction(Signal::SIGALRM, &sa);
+    //! }
     //!
     //! // Set an alarm for 1 second from now.
     //! alarm::set(1);
     //!
     //! let start = Instant::now();
     //! // Pause the process until the alarm signal is received.
-    //! pause();
+    //! let mut sigset = SigSet::empty();
+    //! sigset.add(Signal::SIGALRM);
+    //! sigset.wait();
     //!
     //! assert!(start.elapsed() >= Duration::from_secs(1));
     //! ```
@@ -2536,13 +2548,16 @@
     /// Path to shell
     pub shell: PathBuf,
     /// Login class
-    #[cfg(not(any(target_os = "android", target_os = "linux")))]
+    #[cfg(not(any(target_os = "android", target_os = "fuchsia",
+                  target_os = "linux")))]
     pub class: CString,
     /// Last password change
-    #[cfg(not(any(target_os = "android", target_os = "linux")))]
+    #[cfg(not(any(target_os = "android", target_os = "fuchsia",
+                  target_os = "linux")))]
     pub change: libc::time_t,
     /// Expiration time of account
-    #[cfg(not(any(target_os = "android", target_os = "linux")))]
+    #[cfg(not(any(target_os = "android", target_os = "fuchsia",
+                  target_os = "linux")))]
     pub expire: libc::time_t
 }
 
@@ -2559,11 +2574,14 @@
                 shell: PathBuf::from(OsStr::from_bytes(CStr::from_ptr((*pw).pw_shell).to_bytes())),
                 uid: Uid::from_raw((*pw).pw_uid),
                 gid: Gid::from_raw((*pw).pw_gid),
-                #[cfg(not(any(target_os = "android", target_os = "linux")))]
+                #[cfg(not(any(target_os = "android", target_os = "fuchsia",
+                              target_os = "linux")))]
                 class: CString::new(CStr::from_ptr((*pw).pw_class).to_bytes()).unwrap(),
-                #[cfg(not(any(target_os = "android", target_os = "linux")))]
+                #[cfg(not(any(target_os = "android", target_os = "fuchsia",
+                              target_os = "linux")))]
                 change: (*pw).pw_change,
-                #[cfg(not(any(target_os = "android", target_os = "linux")))]
+                #[cfg(not(any(target_os = "android", target_os = "fuchsia",
+                              target_os = "linux")))]
                 expire: (*pw).pw_expire
             }
         }
@@ -2653,6 +2671,8 @@
 pub struct Group {
     /// Group name
     pub name: String,
+    /// Group password
+    pub passwd: CString,
     /// Group ID
     pub gid: Gid,
     /// List of Group members
@@ -2665,6 +2685,7 @@
         unsafe {
             Group {
                 name: CStr::from_ptr((*gr).gr_name).to_string_lossy().into_owned(),
+                passwd: CString::new(CStr::from_ptr((*gr).gr_passwd).to_bytes()).unwrap(),
                 gid: Gid::from_raw((*gr).gr_gid),
                 mem: Group::members((*gr).gr_mem)
             }
@@ -2771,6 +2792,7 @@
 
 /// Get the name of the terminal device that is open on file descriptor fd
 /// (see [`ttyname(3)`](http://man7.org/linux/man-pages/man3/ttyname.3.html)).
+#[cfg(not(target_os = "fuchsia"))]
 pub fn ttyname(fd: RawFd) -> Result<PathBuf> {
     const PATH_MAX: usize = libc::PATH_MAX as usize;
     let mut buf = vec![0_u8; PATH_MAX];
@@ -2785,3 +2807,23 @@
     buf.truncate(nul);
     Ok(OsString::from_vec(buf).into())
 }
+
+/// Get the effective user ID and group ID associated with a Unix domain socket.
+///
+/// See also [getpeereid(3)](https://www.freebsd.org/cgi/man.cgi?query=getpeereid)
+#[cfg(any(
+    target_os = "macos",
+    target_os = "ios",
+    target_os = "freebsd",
+    target_os = "openbsd",
+    target_os = "netbsd",
+    target_os = "dragonfly",
+))]
+pub fn getpeereid(fd: RawFd) -> Result<(Uid, Gid)> {
+    let mut uid = 1;
+    let mut gid = 1;
+
+    let ret = unsafe { libc::getpeereid(fd, &mut uid, &mut gid) };
+
+    Errno::result(ret).map(|_| (Uid(uid), Gid(gid)))
+}
diff --git a/test/common/mod.rs b/test/common/mod.rs
new file mode 100644
index 0000000..a871b47
--- /dev/null
+++ b/test/common/mod.rs
@@ -0,0 +1,127 @@
+use cfg_if::cfg_if;
+
+#[macro_export] macro_rules! skip {
+    ($($reason: expr),+) => {
+        use ::std::io::{self, Write};
+
+        let stderr = io::stderr();
+        let mut handle = stderr.lock();
+        writeln!(handle, $($reason),+).unwrap();
+        return;
+    }
+}
+
+cfg_if! {
+    if #[cfg(any(target_os = "android", target_os = "linux"))] {
+        #[macro_export] macro_rules! require_capability {
+            ($capname:ident) => {
+                use ::caps::{Capability, CapSet, has_cap};
+
+                if !has_cap(None, CapSet::Effective, Capability::$capname)
+                    .unwrap()
+                {
+                    skip!("Insufficient capabilities. Skipping test.");
+                }
+            }
+        }
+    } else if #[cfg(not(target_os = "redox"))] {
+        #[macro_export] macro_rules! require_capability {
+            ($capname:ident) => {}
+        }
+    }
+}
+
+#[cfg(any(target_os = "linux", target_os= "android"))]
+#[macro_export] macro_rules! skip_if_cirrus {
+    ($reason:expr) => {
+        if std::env::var_os("CIRRUS_CI").is_some() {
+            skip!("{}", $reason);
+        }
+    }
+}
+
+#[cfg(target_os = "freebsd")]
+#[macro_export] macro_rules! skip_if_jailed {
+    ($name:expr) => {
+        use ::sysctl::CtlValue;
+
+        if let CtlValue::Int(1) = ::sysctl::value("security.jail.jailed")
+            .unwrap()
+        {
+            skip!("{} cannot run in a jail. Skipping test.", $name);
+        }
+    }
+}
+
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
+#[macro_export] macro_rules! skip_if_not_root {
+    ($name:expr) => {
+        use nix::unistd::Uid;
+
+        if !Uid::current().is_root() {
+            skip!("{} requires root privileges. Skipping test.", $name);
+        }
+    };
+}
+
+cfg_if! {
+    if #[cfg(any(target_os = "android", target_os = "linux"))] {
+        #[macro_export] macro_rules! skip_if_seccomp {
+            ($name:expr) => {
+                if let Ok(s) = std::fs::read_to_string("/proc/self/status") {
+                    for l in s.lines() {
+                        let mut fields = l.split_whitespace();
+                        if fields.next() == Some("Seccomp:") &&
+                            fields.next() != Some("0")
+                        {
+                            skip!("{} cannot be run in Seccomp mode.  Skipping test.",
+                                stringify!($name));
+                        }
+                    }
+                }
+            }
+        }
+    } else if #[cfg(not(target_os = "redox"))] {
+        #[macro_export] macro_rules! skip_if_seccomp {
+            ($name:expr) => {}
+        }
+    }
+}
+
+cfg_if! {
+    if #[cfg(target_os = "linux")] {
+        #[macro_export] macro_rules! require_kernel_version {
+            ($name:expr, $version_requirement:expr) => {
+                use semver::{Version, VersionReq};
+
+                let version_requirement = VersionReq::parse($version_requirement)
+                        .expect("Bad match_version provided");
+
+                let uname = nix::sys::utsname::uname();
+                println!("{}", uname.sysname());
+                println!("{}", uname.nodename());
+                println!("{}", uname.release());
+                println!("{}", uname.version());
+                println!("{}", uname.machine());
+
+                // Fix stuff that the semver parser can't handle
+                let fixed_release = &uname.release().to_string()
+                    // Fedora 33 reports version as 4.18.el8_2.x86_64 or
+                    // 5.18.200-fc33.x86_64.  Remove the underscore.
+                    .replace("_", "-")
+                    // Cirrus-CI reports version as 4.19.112+ .  Remove the +
+                    .replace("+", "");
+                let mut version = Version::parse(fixed_release).unwrap();
+
+                //Keep only numeric parts
+                version.pre.clear();
+                version.build.clear();
+
+                if !version_requirement.matches(&version) {
+                    skip!("Skip {} because kernel version `{}` doesn't match the requirement `{}`",
+                        stringify!($name), version, version_requirement);
+                }
+            }
+        }
+    }
+}
diff --git a/test/sys/mod.rs b/test/sys/mod.rs
index c4391c7..14b0378 100644
--- a/test/sys/mod.rs
+++ b/test/sys/mod.rs
@@ -21,9 +21,9 @@
 mod test_select;
 #[cfg(any(target_os = "android", target_os = "linux"))]
 mod test_sysinfo;
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
 mod test_termios;
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
 mod test_ioctl;
 mod test_wait;
 mod test_uio;
diff --git a/test/sys/test_aio.rs b/test/sys/test_aio.rs
index 6b9bd91..3878da9 100644
--- a/test/sys/test_aio.rs
+++ b/test/sys/test_aio.rs
@@ -137,6 +137,9 @@
 // in Travis's version of glibc or Linux.  Either way, we must skip the test.
 // https://github.com/nix-rust/nix/issues/1099
 #[cfg_attr(target_os = "linux", ignore)]
+// On Cirrus, aio_suspend is failing with EINVAL
+// https://github.com/nix-rust/nix/issues/1361
+#[cfg_attr(target_os = "macos", ignore)]
 fn test_aio_suspend() {
     const INITIAL: &[u8] = b"abcdef123456";
     const WBUF: &[u8] = b"CDEFG";
@@ -164,7 +167,12 @@
     loop {
         {
             let cbbuf = [&wcb, &rcb];
-            assert!(aio_suspend(&cbbuf[..], Some(timeout)).is_ok());
+            let r = aio_suspend(&cbbuf[..], Some(timeout));
+            match r {
+                Err(Error::Sys(Errno::EINTR)) => continue,
+                Err(e) => panic!("aio_suspend returned {:?}", e),
+                Ok(_) => ()
+            };
         }
         if rcb.error() != Err(Error::from(Errno::EINPROGRESS)) &&
            wcb.error() != Err(Error::from(Errno::EINPROGRESS)) {
diff --git a/test/sys/test_aio_drop.rs b/test/sys/test_aio_drop.rs
index 71a2183..784ee3e 100644
--- a/test/sys/test_aio_drop.rs
+++ b/test/sys/test_aio_drop.rs
@@ -9,6 +9,7 @@
               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_mman.rs b/test/sys/test_mman.rs
new file mode 100644
index 0000000..152fff6
--- /dev/null
+++ b/test/sys/test_mman.rs
@@ -0,0 +1,80 @@
+use nix::Error;
+use nix::libc::{c_void, size_t};
+use nix::sys::mman::{mmap, MapFlags, ProtFlags};
+
+#[cfg(target_os = "linux")]
+use nix::sys::mman::{mremap, MRemapFlags};
+
+#[test]
+fn test_mmap_anonymous() {
+    let ref mut byte = unsafe {
+        let ptr = mmap(std::ptr::null_mut(), 1,
+                       ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
+                       MapFlags::MAP_PRIVATE | MapFlags::MAP_ANONYMOUS, -1, 0)
+                      .unwrap();
+        *(ptr as * mut u8)
+    };
+    assert_eq !(*byte, 0x00u8);
+    *byte = 0xffu8;
+    assert_eq !(*byte, 0xffu8);
+}
+
+#[test]
+#[cfg(target_os = "linux")]
+fn test_mremap_grow() {
+    const ONE_K : size_t = 1024;
+    let slice : &mut[u8] = unsafe {
+        let mem = mmap(std::ptr::null_mut(), ONE_K,
+                       ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
+                       MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, -1, 0)
+                      .unwrap();
+        std::slice::from_raw_parts_mut(mem as * mut u8, ONE_K)
+    };
+    assert_eq !(slice[ONE_K - 1], 0x00);
+    slice[ONE_K - 1] = 0xFF;
+    assert_eq !(slice[ONE_K - 1], 0xFF);
+
+    let slice : &mut[u8] = unsafe {
+        let mem = mremap(slice.as_mut_ptr() as * mut c_void, ONE_K, 10 * ONE_K,
+                         MRemapFlags::MREMAP_MAYMOVE, None)
+                      .unwrap();
+        std::slice::from_raw_parts_mut(mem as * mut u8, 10 * ONE_K)
+    };
+
+    // The first KB should still have the old data in it.
+    assert_eq !(slice[ONE_K - 1], 0xFF);
+
+    // The additional range should be zero-init'd and accessible.
+    assert_eq !(slice[10 * ONE_K - 1], 0x00);
+    slice[10 * ONE_K - 1] = 0xFF;
+    assert_eq !(slice[10 * ONE_K - 1], 0xFF);
+}
+
+#[test]
+#[cfg(target_os = "linux")]
+fn test_mremap_shrink() {
+    const ONE_K : size_t = 1024;
+    let slice : &mut[u8] = unsafe {
+        let mem = mmap(std::ptr::null_mut(), 10 * ONE_K,
+                       ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
+                       MapFlags::MAP_ANONYMOUS | MapFlags::MAP_PRIVATE, -1, 0)
+                      .unwrap();
+        std::slice::from_raw_parts_mut(mem as * mut u8, ONE_K)
+    };
+    assert_eq !(slice[ONE_K - 1], 0x00);
+    slice[ONE_K - 1] = 0xFF;
+    assert_eq !(slice[ONE_K - 1], 0xFF);
+
+    let slice : &mut[u8] = unsafe {
+        let mem = mremap(slice.as_mut_ptr() as * mut c_void, 10 * ONE_K, ONE_K,
+                         MRemapFlags::empty(), None)
+                      .unwrap();
+        // Since we didn't supply MREMAP_MAYMOVE, the address should be the
+        // same.
+        assert_eq !(mem, slice.as_mut_ptr() as * mut c_void);
+        std::slice::from_raw_parts_mut(mem as * mut u8, ONE_K)
+    };
+
+    // The first KB should still be accessible and have the old data in it.
+    assert_eq !(slice[ONE_K - 1], 0xFF);
+}
diff --git a/test/sys/test_ptrace.rs b/test/sys/test_ptrace.rs
index 3b60dd7..b9793b3 100644
--- a/test/sys/test_ptrace.rs
+++ b/test/sys/test_ptrace.rs
@@ -8,6 +8,8 @@
 #[cfg(any(target_os = "android", target_os = "linux"))]
 use std::mem;
 
+use crate::*;
+
 #[test]
 fn test_ptrace() {
     // Just make sure ptrace can be called at all, for now.
@@ -98,7 +100,7 @@
             ptrace::cont(child, Some(Signal::SIGKILL)).unwrap();
             match waitpid(child, None) {
                 Ok(WaitStatus::Signaled(pid, Signal::SIGKILL, _)) if pid == child => {
-                    // FIXME It's been observed on some systems (apple) the 
+                    // FIXME It's been observed on some systems (apple) the
                     // tracee may not be killed but remain as a zombie process
                     // affecting other wait based tests. Add an extra kill just
                     // to make sure there are no zombies.
@@ -148,11 +150,11 @@
             // set this option to recognize syscall-stops
             ptrace::setoptions(child, ptrace::Options::PTRACE_O_TRACESYSGOOD).unwrap();
 
-            #[cfg(target_pointer_width = "64")]
-            let get_syscall_id = || ptrace::getregs(child).unwrap().orig_rax as i64;
+            #[cfg(target_arch = "x86_64")]
+            let get_syscall_id = || ptrace::getregs(child).unwrap().orig_rax as libc::c_long;
 
-            #[cfg(target_pointer_width = "32")]
-            let get_syscall_id = || ptrace::getregs(child).unwrap().orig_eax as i32;
+            #[cfg(target_arch = "x86")]
+            let get_syscall_id = || ptrace::getregs(child).unwrap().orig_eax as libc::c_long;
 
             // kill entry
             ptrace::syscall(child, None).unwrap();
diff --git a/test/sys/test_signal.rs b/test/sys/test_signal.rs
index 5e0b276..ae22527 100644
--- a/test/sys/test_signal.rs
+++ b/test/sys/test_signal.rs
@@ -12,6 +12,7 @@
 }
 
 #[test]
+#[cfg(not(target_os = "fuchsia"))]
 fn test_killpg_none() {
     killpg(getpgrp(), None)
         .expect("Should be able to send signal to my process group.");
diff --git a/test/sys/test_socket.rs b/test/sys/test_socket.rs
index 1003598..7eab28c 100644
--- a/test/sys/test_socket.rs
+++ b/test/sys/test_socket.rs
@@ -1,4 +1,3 @@
-use nix::ifaddrs::InterfaceAddress;
 use nix::sys::socket::{AddressFamily, InetAddr, UnixAddr, getsockname};
 use std::collections::hash_map::DefaultHasher;
 use std::hash::{Hash, Hasher};
@@ -9,6 +8,8 @@
 use std::str::FromStr;
 use libc::c_char;
 use tempfile;
+#[cfg(any(target_os = "linux", target_os= "android"))]
+use crate::*;
 
 #[test]
 pub fn test_inetv4_addr_to_sock_addr() {
@@ -237,6 +238,9 @@
         use nix::sys::socket::sockopt::{UdpGroSegment, UdpGsoSegment};
 
         #[test]
+        // 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", target_arch="i686")), ignore)]
         pub fn gso() {
             require_kernel_version!(udp_offload::gso, ">= 4.18");
 
@@ -288,6 +292,9 @@
         }
 
         #[test]
+        // 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", target_arch="i686")), ignore)]
         pub fn gro() {
             require_kernel_version!(udp_offload::gro, ">= 5.3");
 
@@ -437,6 +444,76 @@
 
         send_thread.join().unwrap();
     }
+
+    #[cfg(any(
+        target_os = "linux",
+        target_os = "android",
+        target_os = "freebsd",
+        target_os = "netbsd",
+    ))]
+    #[test]
+    pub fn udp_recvmmsg_dontwait_short_read() {
+        use nix::sys::uio::IoVec;
+        use nix::sys::socket::{MsgFlags, recvmmsg};
+
+        const NUM_MESSAGES_SENT: usize = 2;
+        const DATA: [u8; 4] = [1,2,3,4];
+
+        let std_sa = SocketAddr::from_str("127.0.0.1:6799").unwrap();
+        let inet_addr = InetAddr::from_std(&std_sa);
+        let sock_addr = SockAddr::new_inet(inet_addr);
+
+        let rsock = socket(AddressFamily::Inet,
+            SockType::Datagram,
+            SockFlag::empty(),
+            None
+        ).unwrap();
+        bind(rsock, &sock_addr).unwrap();
+        let ssock = socket(
+            AddressFamily::Inet,
+            SockType::Datagram,
+            SockFlag::empty(),
+            None,
+        ).expect("send socket failed");
+
+        let send_thread = thread::spawn(move || {
+            for _ in 0..NUM_MESSAGES_SENT {
+                sendto(ssock, &DATA[..], &sock_addr, MsgFlags::empty()).unwrap();
+            }
+        });
+        // Ensure we've sent all the messages before continuing so `recvmmsg`
+        // will return right away
+        send_thread.join().unwrap();
+
+        let mut msgs = std::collections::LinkedList::new();
+
+        // Buffers to receive >`NUM_MESSAGES_SENT` messages to ensure `recvmmsg`
+        // will return when there are fewer than requested messages in the
+        // kernel buffers when using `MSG_DONTWAIT`.
+        let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT + 2];
+        let iovs: Vec<_> = receive_buffers.iter_mut().map(|buf| {
+            [IoVec::from_mut_slice(&mut buf[..])]
+        }).collect();
+
+        for iov in &iovs {
+            msgs.push_back(RecvMmsgData {
+                iov: iov,
+                cmsg_buffer: None,
+            })
+        };
+
+        let res = recvmmsg(rsock, &mut msgs, MsgFlags::MSG_DONTWAIT, None).expect("recvmmsg");
+        assert_eq!(res.len(), NUM_MESSAGES_SENT);
+
+        for RecvMsg { address, bytes, .. } in res.into_iter() {
+            assert_eq!(AddressFamily::Inet, address.unwrap().family());
+            assert_eq!(DATA.len(), bytes);
+        }
+
+        for buf in &receive_buffers[..NUM_MESSAGES_SENT] {
+            assert_eq!(&buf[..DATA.len()], DATA);
+        }
+    }
 }
 
 // Test error handling of our recvmsg wrapper
@@ -522,12 +599,13 @@
                            ControlMessage, MsgFlags};
     use nix::sys::socket::sockopt::AlgSetKey;
 
+    skip_if_cirrus!("Fails for an unknown reason Cirrus CI.  Bug #1352");
     // Travis's seccomp profile blocks AF_ALG
     // https://docs.docker.com/engine/security/seccomp/
     skip_if_seccomp!(test_af_alg_cipher);
 
     let alg_type = "skcipher";
-    let alg_name = "ctr(aes)";
+    let alg_name = "ctr-aes-aesni";
     // 256-bits secret key
     let key = vec![0u8; 32];
     // 16-bytes IV
@@ -590,6 +668,7 @@
                            ControlMessage, MsgFlags};
     use nix::sys::socket::sockopt::{AlgSetKey, AlgSetAeadAuthSize};
 
+    skip_if_cirrus!("Fails for an unknown reason Cirrus CI.  Bug #1352");
     // Travis's seccomp profile blocks AF_ALG
     // https://docs.docker.com/engine/security/seccomp/
     skip_if_seccomp!(test_af_alg_aead);
@@ -948,7 +1027,7 @@
 fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
     use libc::ucred;
     use nix::sys::uio::IoVec;
-    use nix::unistd::{pipe, read, write, close, getpid, getuid, getgid};
+    use nix::unistd::{pipe, write, close, getpid, getuid, getgid};
     use nix::sys::socket::{socketpair, sendmsg, recvmsg, setsockopt,
                            SockType, SockFlag,
                            ControlMessage, ControlMessageOwned, MsgFlags};
@@ -1081,7 +1160,7 @@
     target_os = "netbsd",
     target_os = "openbsd",
 ))]
-fn loopback_address(family: AddressFamily) -> Option<InterfaceAddress> {
+fn loopback_address(family: AddressFamily) -> Option<nix::ifaddrs::InterfaceAddress> {
     use std::io;
     use std::io::Write;
     use nix::ifaddrs::getifaddrs;
diff --git a/test/sys/test_sockopt.rs b/test/sys/test_sockopt.rs
index 8e2adce..5606593 100644
--- a/test/sys/test_sockopt.rs
+++ b/test/sys/test_sockopt.rs
@@ -1,5 +1,7 @@
 use rand::{thread_rng, Rng};
 use nix::sys::socket::{socket, sockopt, getsockopt, setsockopt, AddressFamily, SockType, SockFlag, SockProtocol};
+#[cfg(any(target_os = "android", target_os = "linux"))]
+use crate::*;
 
 #[cfg(target_os = "linux")]
 #[test]
diff --git a/test/sys/test_uio.rs b/test/sys/test_uio.rs
index 4fa838c..8d22bf1 100644
--- a/test/sys/test_uio.rs
+++ b/test/sys/test_uio.rs
@@ -203,6 +203,7 @@
     use nix::unistd::ForkResult::*;
     use nix::sys::signal::*;
     use nix::sys::wait::*;
+    use crate::*;
 
     require_capability!(CAP_SYS_PTRACE);
     let _ = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
diff --git a/test/sys/test_wait.rs b/test/sys/test_wait.rs
index d105625..5bb298e 100644
--- a/test/sys/test_wait.rs
+++ b/test/sys/test_wait.rs
@@ -67,6 +67,7 @@
     use nix::unistd::*;
     use nix::unistd::ForkResult::*;
     use libc::_exit;
+    use crate::*;
 
     fn ptrace_child() -> ! {
         ptrace::traceme().unwrap();
diff --git a/test/test.rs b/test/test.rs
index 8ad09b6..5a5330b 100644
--- a/test/test.rs
+++ b/test/test.rs
@@ -5,111 +5,7 @@
 #[macro_use]
 extern crate lazy_static;
 
-macro_rules! skip {
-    ($($reason: expr),+) => {
-        use ::std::io::{self, Write};
-
-        let stderr = io::stderr();
-        let mut handle = stderr.lock();
-        writeln!(handle, $($reason),+).unwrap();
-        return;
-    }
-}
-
-cfg_if! {
-    if #[cfg(any(target_os = "android", target_os = "linux"))] {
-        macro_rules! require_capability {
-            ($capname:ident) => {
-                use ::caps::{Capability, CapSet, has_cap};
-
-                if !has_cap(None, CapSet::Effective, Capability::$capname)
-                    .unwrap()
-                {
-                    skip!("Insufficient capabilities. Skipping test.");
-                }
-            }
-        }
-    } else if #[cfg(not(target_os = "redox"))] {
-        macro_rules! require_capability {
-            ($capname:ident) => {}
-        }
-    }
-}
-
-#[cfg(target_os = "freebsd")]
-macro_rules! skip_if_jailed {
-    ($name:expr) => {
-        use ::sysctl::CtlValue;
-
-        if let CtlValue::Int(1) = ::sysctl::value("security.jail.jailed")
-            .unwrap()
-        {
-            skip!("{} cannot run in a jail. Skipping test.", $name);
-        }
-    }
-}
-
-#[cfg(not(target_os = "redox"))]
-macro_rules! skip_if_not_root {
-    ($name:expr) => {
-        use nix::unistd::Uid;
-
-        if !Uid::current().is_root() {
-            skip!("{} requires root privileges. Skipping test.", $name);
-        }
-    };
-}
-
-cfg_if! {
-    if #[cfg(any(target_os = "android", target_os = "linux"))] {
-        macro_rules! skip_if_seccomp {
-            ($name:expr) => {
-                if let Ok(s) = std::fs::read_to_string("/proc/self/status") {
-                    for l in s.lines() {
-                        let mut fields = l.split_whitespace();
-                        if fields.next() == Some("Seccomp:") &&
-                            fields.next() != Some("0")
-                        {
-                            skip!("{} cannot be run in Seccomp mode.  Skipping test.",
-                                stringify!($name));
-                        }
-                    }
-                }
-            }
-        }
-    } else if #[cfg(not(target_os = "redox"))] {
-        macro_rules! skip_if_seccomp {
-            ($name:expr) => {}
-        }
-    }
-}
-
-cfg_if! {
-    if #[cfg(target_os = "linux")] {
-        macro_rules! require_kernel_version {
-            ($name:expr, $version_requirement:expr) => {
-                use semver::{Version, VersionReq};
-
-                let version_requirement = VersionReq::parse($version_requirement)
-                        .expect("Bad match_version provided");
-
-                let uname = nix::sys::utsname::uname();
-
-                let mut version = Version::parse(uname.release()).unwrap();
-
-                //Keep only numeric parts
-                version.pre.clear();
-                version.build.clear();
-
-                if !version_requirement.matches(&version) {
-                    skip!("Skip {} because kernel version `{}` doesn't match the requirement `{}`",
-                        stringify!($name), version, version_requirement);
-                }
-            }
-        }
-    }
-}
-
+mod common;
 mod sys;
 #[cfg(not(target_os = "redox"))]
 mod test_dir;
@@ -127,7 +23,7 @@
 mod test_net;
 mod test_nix_path;
 mod test_poll;
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
 mod test_pty;
 #[cfg(any(target_os = "android",
           target_os = "linux"))]
@@ -147,6 +43,7 @@
 use std::sync::{Mutex, RwLock, RwLockWriteGuard};
 use nix::unistd::{chdir, getcwd, read};
 
+
 /// Helper function analogous to `std::io::Read::read_exact`, but for `RawFD`s
 fn read_exact(f: RawFd, buf: &mut  [u8]) {
     let mut len = 0;
diff --git a/test/test_dir.rs b/test/test_dir.rs
index c5f9c51..505277e 100644
--- a/test/test_dir.rs
+++ b/test/test_dir.rs
@@ -34,7 +34,9 @@
                             Mode::empty()).unwrap();
     let entries1: Vec<_> = dir.iter().map(|e| e.unwrap().file_name().to_owned()).collect();
     let entries2: Vec<_> = dir.iter().map(|e| e.unwrap().file_name().to_owned()).collect();
+    let entries3: Vec<_> = dir.into_iter().map(|e| e.unwrap().file_name().to_owned()).collect();
     assert_eq!(entries1, entries2);
+    assert_eq!(entries2, entries3);
 }
 
 #[test]
diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs
index 2971907..5d1bafe 100644
--- a/test/test_fcntl.rs
+++ b/test/test_fcntl.rs
@@ -19,6 +19,8 @@
 #[cfg(not(target_os = "redox"))]
 use std::os::unix::fs;
 
+use crate::*;
+
 #[test]
 #[cfg(not(target_os = "redox"))]
 fn test_openat() {
@@ -93,6 +95,8 @@
 
     use tempfile::{tempfile, NamedTempFile};
 
+    use crate::*;
+
     /// This test creates a temporary file containing the contents
     /// 'foobarbaz' and uses the `copy_file_range` call to transfer
     /// 3 bytes at offset 3 (`bar`) to another empty file at offset 0. The
@@ -328,7 +332,7 @@
           target_os = "fuchsia",
           any(target_os = "wasi", target_env = "wasi"),
           target_env = "uclibc",
-          target_env = "freebsd"))]
+          target_os = "freebsd"))]
 mod test_posix_fadvise {
 
     use tempfile::NamedTempFile;
diff --git a/test/test_kmod/mod.rs b/test/test_kmod/mod.rs
index e7472ab..fb7260b 100644
--- a/test/test_kmod/mod.rs
+++ b/test/test_kmod/mod.rs
@@ -2,6 +2,7 @@
 use std::path::PathBuf;
 use std::process::Command;
 use tempfile::{tempdir, TempDir};
+use crate::*;
 
 fn compile_kernel_module() -> (PathBuf, String, TempDir) {
     let _m = crate::FORK_MTX
diff --git a/test/test_mount.rs b/test/test_mount.rs
index 605276b..c1b6c8a 100644
--- a/test/test_mount.rs
+++ b/test/test_mount.rs
@@ -1,3 +1,5 @@
+mod common;
+
 // Impelmentation note: to allow unprivileged users to run it, this test makes
 // use of user and mount namespaces. On systems that allow unprivileged user
 // namespaces (Linux >= 3.8 compiled with CONFIG_USER_NS), the test should run
@@ -222,6 +224,7 @@
     use test_mount::{setup_namespaces, test_mount_tmpfs_without_flags_allows_rwx,
                      test_mount_rdonly_disallows_write, test_mount_noexec_disallows_exec,
                      test_mount_bind};
+    skip_if_cirrus!("Fails for an unknown reason Cirrus CI.  Bug #1351");
     setup_namespaces();
 
     run_tests!(test_mount_tmpfs_without_flags_allows_rwx,
diff --git a/test/test_mq.rs b/test/test_mq.rs
index ecee200..1667a35 100644
--- a/test/test_mq.rs
+++ b/test/test_mq.rs
@@ -1,17 +1,15 @@
-use libc::c_long;
-
 use std::ffi::CString;
 use std::str;
 
 use nix::errno::Errno::*;
 use nix::Error::Sys;
-use nix::mqueue::{mq_open, mq_close, mq_send, mq_receive};
+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;
 
 #[test]
 fn test_mq_send_and_receive() {
-    const MSG_SIZE: c_long =  32;
+    const MSG_SIZE: mq_attr_member_t = 32;
     let attr =  MqAttr::new(0, 10, MSG_SIZE, 0);
     let mq_name= &CString::new(b"/a_nix_test_queue".as_ref()).unwrap();
 
@@ -43,7 +41,7 @@
 #[cfg(not(any(target_os = "netbsd")))]
 fn test_mq_getattr() {
     use nix::mqueue::mq_getattr;
-    const MSG_SIZE: c_long =  32;
+    const MSG_SIZE: mq_attr_member_t = 32;
     let initial_attr =  MqAttr::new(0, 10, MSG_SIZE, 0);
     let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap();
     let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
@@ -66,7 +64,7 @@
 #[cfg_attr(any(target_arch = "mips", target_arch = "mips64"), ignore)]
 fn test_mq_setattr() {
     use nix::mqueue::{mq_getattr, mq_setattr};
-    const MSG_SIZE: c_long =  32;
+    const MSG_SIZE: mq_attr_member_t = 32;
     let initial_attr =  MqAttr::new(0, 10, MSG_SIZE, 0);
     let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap();
     let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
@@ -87,7 +85,7 @@
     // O_NONBLOCK can be set (see tests below)
     assert_ne!(new_attr_get, new_attr);
 
-    let new_attr_non_blocking =  MqAttr::new(MQ_OFlag::O_NONBLOCK.bits() as c_long, 10, MSG_SIZE, 0);
+    let new_attr_non_blocking =  MqAttr::new(MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t, 10, MSG_SIZE, 0);
     mq_setattr(mqd, &new_attr_non_blocking).unwrap();
     let new_attr_get = mq_getattr(mqd).unwrap();
 
@@ -103,7 +101,7 @@
 #[cfg_attr(any(target_arch = "mips", target_arch = "mips64"), ignore)]
 fn test_mq_set_nonblocking() {
     use nix::mqueue::{mq_getattr, mq_set_nonblock, mq_remove_nonblock};
-    const MSG_SIZE: c_long =  32;
+    const MSG_SIZE: mq_attr_member_t = 32;
     let initial_attr =  MqAttr::new(0, 10, MSG_SIZE, 0);
     let mq_name = &CString::new(b"/attr_test_get_attr".as_ref()).unwrap();
     let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
@@ -116,7 +114,7 @@
     let mqd = r.unwrap();
     mq_set_nonblock(mqd).unwrap();
     let new_attr = mq_getattr(mqd);
-    assert_eq!(new_attr.unwrap().flags(), MQ_OFlag::O_NONBLOCK.bits() as c_long);
+    assert_eq!(new_attr.unwrap().flags(), MQ_OFlag::O_NONBLOCK.bits() as mq_attr_member_t);
     mq_remove_nonblock(mqd).unwrap();
     let new_attr = mq_getattr(mqd);
     assert_eq!(new_attr.unwrap().flags(), 0);
@@ -127,7 +125,7 @@
 #[cfg(not(any(target_os = "netbsd")))]
 fn test_mq_unlink() {
     use nix::mqueue::mq_unlink;
-    const MSG_SIZE: c_long =  32;
+    const MSG_SIZE: mq_attr_member_t = 32;
     let initial_attr =  MqAttr::new(0, 10, MSG_SIZE, 0);
     let mq_name_opened = &CString::new(b"/mq_unlink_test".as_ref()).unwrap();
     let mq_name_not_opened = &CString::new(b"/mq_unlink_test".as_ref()).unwrap();
diff --git a/test/test_poll.rs b/test/test_poll.rs
index d1974ac..a5e2d25 100644
--- a/test/test_poll.rs
+++ b/test/test_poll.rs
@@ -1,5 +1,21 @@
-use nix::poll::{PollFlags, poll, PollFd};
-use nix::unistd::{write, pipe};
+use nix::{
+    Error,
+    errno::Errno,
+    poll::{PollFlags, poll, PollFd},
+    unistd::{write, pipe}
+};
+
+macro_rules! loop_while_eintr {
+    ($poll_expr: expr) => {
+        loop {
+            match $poll_expr {
+                Ok(nfds) => break nfds,
+                Err(Error::Sys(Errno::EINTR)) => (),
+                Err(e) => panic!(e)
+            }
+        }
+    }
+}
 
 #[test]
 fn test_poll() {
@@ -7,7 +23,7 @@
     let mut fds = [PollFd::new(r, PollFlags::POLLIN)];
 
     // Poll an idle pipe.  Should timeout
-    let nfds = poll(&mut fds, 100).unwrap();
+    let nfds = loop_while_eintr!(poll(&mut fds, 100));
     assert_eq!(nfds, 0);
     assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN));
 
@@ -37,7 +53,8 @@
     let mut fds = [PollFd::new(r, PollFlags::POLLIN)];
 
     // Poll an idle pipe.  Should timeout
-    let nfds = ppoll(&mut fds, Some(timeout), SigSet::empty()).unwrap();
+    let sigset = SigSet::empty();
+    let nfds = loop_while_eintr!(ppoll(&mut fds, Some(timeout), sigset));
     assert_eq!(nfds, 0);
     assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN));
 
diff --git a/test/test_ptymaster_drop.rs b/test/test_ptymaster_drop.rs
index 5a5c55d..ff939b9 100644
--- a/test/test_ptymaster_drop.rs
+++ b/test/test_ptymaster_drop.rs
@@ -1,4 +1,4 @@
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
 mod t {
     use nix::fcntl::OFlag;
     use nix::pty::*;
diff --git a/test/test_unistd.rs b/test/test_unistd.rs
index c7a75fb..16a8a05 100644
--- a/test/test_unistd.rs
+++ b/test/test_unistd.rs
@@ -7,7 +7,7 @@
 use nix::sys::signal::{SaFlags, SigAction, SigHandler, SigSet, Signal, sigaction};
 use nix::sys::wait::*;
 use nix::sys::stat::{self, Mode, SFlag};
-#[cfg(not(target_os = "redox"))]
+#[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"))]
@@ -19,13 +19,14 @@
 use std::fs::DirBuilder;
 use std::fs::{self, File};
 use std::io::Write;
-use std::mem;
 use std::os::unix::prelude::*;
 #[cfg(not(target_os = "redox"))]
 use std::path::Path;
 use tempfile::{tempdir, tempfile};
 use libc::{_exit, off_t};
 
+use crate::*;
+
 #[test]
 #[cfg(not(any(target_os = "netbsd")))]
 fn test_fork_and_waitpid() {
@@ -200,7 +201,7 @@
 
 #[test]
 // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms
-#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))]
+#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "fuchsia")))]
 fn test_setgroups() {
     // Skip this test when not run as root as `setgroups()` requires root.
     skip_if_not_root!("test_setgroups");
@@ -223,7 +224,7 @@
 
 #[test]
 // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms
-#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))]
+#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox", target_os = "fuchsia")))]
 fn test_initgroups() {
     // Skip this test when not run as root as `initgroups()` and `setgroups()`
     // require root.
@@ -259,18 +260,24 @@
 
     #[cfg(test)]
     mod $test_name {
+    use std::ffi::CStr;
     use super::*;
 
+    const EMPTY: &'static [u8] = b"\0";
+    const DASH_C: &'static [u8] = b"-c\0";
+    const BIGARG: &'static [u8] = b"echo nix!!! && echo foo=$foo && echo baz=$baz\0";
+    const FOO: &'static [u8] = b"foo=bar\0";
+    const BAZ: &'static [u8] = b"baz=quux\0";
+
     fn syscall_cstr_ref() -> Result<std::convert::Infallible, nix::Error> {
         $syscall(
             $exe,
             $(CString::new($pathname).unwrap().as_c_str(), )*
-            &[CString::new(b"".as_ref()).unwrap().as_c_str(),
-              CString::new(b"-c".as_ref()).unwrap().as_c_str(),
-              CString::new(b"echo nix!!! && echo foo=$foo && echo baz=$baz"
-                           .as_ref()).unwrap().as_c_str()],
-            &[CString::new(b"foo=bar".as_ref()).unwrap().as_c_str(),
-              CString::new(b"baz=quux".as_ref()).unwrap().as_c_str()]
+            &[CStr::from_bytes_with_nul(EMPTY).unwrap(),
+              CStr::from_bytes_with_nul(DASH_C).unwrap(),
+              CStr::from_bytes_with_nul(BIGARG).unwrap()],
+            &[CStr::from_bytes_with_nul(FOO).unwrap(),
+              CStr::from_bytes_with_nul(BAZ).unwrap()]
             $(, $flags)*)
     }
 
@@ -278,12 +285,11 @@
         $syscall(
             $exe,
             $(CString::new($pathname).unwrap().as_c_str(), )*
-            &[CString::new(b"".as_ref()).unwrap(),
-              CString::new(b"-c".as_ref()).unwrap(),
-              CString::new(b"echo nix!!! && echo foo=$foo && echo baz=$baz"
-                           .as_ref()).unwrap()],
-            &[CString::new(b"foo=bar".as_ref()).unwrap(),
-              CString::new(b"baz=quux".as_ref()).unwrap()]
+            &[CString::from(CStr::from_bytes_with_nul(EMPTY).unwrap()),
+              CString::from(CStr::from_bytes_with_nul(DASH_C).unwrap()),
+              CString::from(CStr::from_bytes_with_nul(BIGARG).unwrap())],
+            &[CString::from(CStr::from_bytes_with_nul(FOO).unwrap()),
+              CString::from(CStr::from_bytes_with_nul(BAZ).unwrap())]
             $(, $flags)*)
     }
 
@@ -329,11 +335,17 @@
         }
     }
 
+    // These tests frequently fail on musl, probably due to
+        // https://github.com/nix-rust/nix/issues/555
+    #[cfg_attr(target_env = "musl", ignore)]
     #[test]
     fn test_cstr_ref() {
         common_test(syscall_cstr_ref);
     }
 
+    // These tests frequently fail on musl, probably due to
+        // https://github.com/nix-rust/nix/issues/555
+    #[cfg_attr(target_env = "musl", ignore)]
     #[test]
     fn test_cstring() {
         common_test(syscall_cstring);
@@ -349,6 +361,8 @@
         execve_test_factory!(test_fexecve, fexecve, File::open("/system/bin/sh").unwrap().into_raw_fd());
     } else if #[cfg(any(target_os = "freebsd",
                         target_os = "linux"))] {
+        // These tests frequently fail on musl, probably due to
+        // https://github.com/nix-rust/nix/issues/555
         execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap().as_c_str());
         execve_test_factory!(test_fexecve, fexecve, File::open("/bin/sh").unwrap().into_raw_fd());
     } else if #[cfg(any(target_os = "dragonfly",
@@ -371,13 +385,16 @@
 cfg_if!{
     if #[cfg(target_os = "android")] {
         use nix::fcntl::AtFlags;
-        execve_test_factory!(test_execveat_empty, execveat, File::open("/system/bin/sh").unwrap().into_raw_fd(),
+        execve_test_factory!(test_execveat_empty, execveat,
+                             File::open("/system/bin/sh").unwrap().into_raw_fd(),
                              "", AtFlags::AT_EMPTY_PATH);
-        execve_test_factory!(test_execveat_relative, execveat, File::open("/system/bin/").unwrap().into_raw_fd(),
+        execve_test_factory!(test_execveat_relative, execveat,
+                             File::open("/system/bin/").unwrap().into_raw_fd(),
                              "./sh", AtFlags::empty());
-        execve_test_factory!(test_execveat_absolute, execveat, File::open("/").unwrap().into_raw_fd(),
+        execve_test_factory!(test_execveat_absolute, execveat,
+                             File::open("/").unwrap().into_raw_fd(),
                              "/system/bin/sh", AtFlags::empty());
-    } else if #[cfg(all(target_os = "linux"), any(target_arch ="x86_64", target_arch ="x86"))] {
+    } else if #[cfg(all(target_os = "linux", any(target_arch ="x86_64", target_arch ="x86")))] {
         use nix::fcntl::AtFlags;
         execve_test_factory!(test_execveat_empty, execveat, File::open("/bin/sh").unwrap().into_raw_fd(),
                              "", AtFlags::AT_EMPTY_PATH);
@@ -389,6 +406,7 @@
 }
 
 #[test]
+#[cfg(not(target_os = "fuchsia"))]
 fn test_fchdir() {
     // fchdir changes the process's cwd
     let _dr = crate::DirRestore::new();
@@ -459,9 +477,7 @@
     fchown(fd, uid, gid).unwrap();
     fchown(fd, uid, None).unwrap();
     fchown(fd, None, gid).unwrap();
-
-    mem::drop(path);
-    fchown(fd, uid, gid).unwrap_err();
+    fchown(999999999, uid, gid).unwrap_err();
 }
 
 #[test]
@@ -537,7 +553,7 @@
                 skip_if_jailed!("test_acct");
             }
         }
-    } else if #[cfg(not(target_os = "redox"))] {
+    } else if #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] {
         macro_rules! require_acct{
             () => {
                 skip_if_not_root!("test_acct");
@@ -547,7 +563,7 @@
 }
 
 #[test]
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
 fn test_acct() {
     use tempfile::NamedTempFile;
     use std::process::Command;
@@ -634,7 +650,7 @@
 }
 
 #[test]
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
 fn test_truncate() {
     let tempdir = tempdir().unwrap();
     let path = tempdir.path().join("file");
@@ -684,6 +700,12 @@
 #[test]
 #[cfg(not(target_os = "redox"))]
 fn test_alarm() {
+    use std::{
+        time::{Duration, Instant,},
+        thread
+    };
+
+    // Maybe other tests that fork interfere with this one?
     let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
 
     let handler = SigHandler::Handler(alarm_signal_handler);
@@ -701,8 +723,16 @@
 
     // We should be woken up after 1 second by the alarm, so we'll sleep for 2
     // seconds to be sure.
-    sleep(2);
-    assert_eq!(unsafe { ALARM_CALLED }, true, "expected our alarm signal handler to be called");
+    let starttime = Instant::now();
+    loop {
+        thread::sleep(Duration::from_millis(100));
+        if unsafe { ALARM_CALLED} {
+            break;
+        }
+        if starttime.elapsed() > Duration::from_secs(3) {
+            panic!("Timeout waiting for SIGALRM");
+        }
+    }
 
     // Reset the signal.
     unsafe {
@@ -976,8 +1006,9 @@
     let nobody = User::from_name("nobody").unwrap().unwrap();
 
     // create a temporary file with permissions '-rw-r-----'
-    let file = tempfile::NamedTempFile::new().unwrap();
+    let file = tempfile::NamedTempFile::new_in("/var/tmp").unwrap();
     let temp_path = file.into_temp_path();
+    dbg!(&temp_path);
     let temp_path_2 = (&temp_path).to_path_buf();
     let mut permissions = fs::metadata(&temp_path).unwrap().permissions();
     permissions.set_mode(640);
@@ -1003,7 +1034,7 @@
 }
 
 #[test]
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
 fn test_ttyname() {
     let fd = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed");
     assert!(fd.as_raw_fd() > 0);
@@ -1026,7 +1057,7 @@
 }
 
 #[test]
-#[cfg(not(target_os = "redox"))]
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
 fn test_ttyname_not_pty() {
     let fd = File::open("/dev/zero").unwrap();
     assert!(fd.as_raw_fd() > 0);
@@ -1034,13 +1065,46 @@
 }
 
 #[test]
-#[cfg(all(not(target_os = "redox"), not(target_env = "musl")))]
+#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
 fn test_ttyname_invalid_fd() {
     assert_eq!(ttyname(-1), Err(Error::Sys(Errno::EBADF)));
 }
 
 #[test]
-#[cfg(all(not(target_os = "redox"), target_env = "musl"))]
-fn test_ttyname_invalid_fd() {
-    assert_eq!(ttyname(-1), Err(Error::Sys(Errno::ENOTTY)));
+#[cfg(any(
+    target_os = "macos",
+    target_os = "ios",
+    target_os = "freebsd",
+    target_os = "openbsd",
+    target_os = "netbsd",
+    target_os = "dragonfly",
+))]
+fn test_getpeereid() {
+    use std::os::unix::net::UnixStream;
+    let (sock_a, sock_b) = UnixStream::pair().unwrap();
+
+    let (uid_a, gid_a) = getpeereid(sock_a.as_raw_fd()).unwrap();
+    let (uid_b, gid_b) = getpeereid(sock_b.as_raw_fd()).unwrap();
+
+    let uid = geteuid();
+    let gid = getegid();
+
+    assert_eq!(uid, uid_a);
+    assert_eq!(gid, gid_a);
+    assert_eq!(uid_a, uid_b);
+    assert_eq!(gid_a, gid_b);
+}
+
+#[test]
+#[cfg(any(
+    target_os = "macos",
+    target_os = "ios",
+    target_os = "freebsd",
+    target_os = "openbsd",
+    target_os = "netbsd",
+    target_os = "dragonfly",
+))]
+fn test_getpeereid_invalid_fd() {
+    // getpeereid is not POSIX, so error codes are inconsistent between different Unices.
+    assert!(getpeereid(-1).is_err());
 }