public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
From: "Yixun Lan" <dlan@gentoo.org>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/riscv:master commit in: www-client/firefox/files/, www-client/firefox/
Date: Wed, 20 Apr 2022 13:23:28 +0000 (UTC)	[thread overview]
Message-ID: <1650460949.07c4b52e96d933d680ba43f71849bae09abd41f2.dlan@gentoo> (raw)

commit:     07c4b52e96d933d680ba43f71849bae09abd41f2
Author:     Yu Gu <guyu2876 <AT> gmail <DOT> com>
AuthorDate: Wed Apr 20 13:11:25 2022 +0000
Commit:     Yixun Lan <dlan <AT> gentoo <DOT> org>
CommitDate: Wed Apr 20 13:22:29 2022 +0000
URL:        https://gitweb.gentoo.org/proj/riscv.git/commit/?id=07c4b52e

www-client/firefox: bump to 98.0.2

Compared to the original ebuild, a patch was added and
the sandbox was disabled because too many failures with 'enable-sanbox' enabled
This feature is temporarily not supported on riscv.

Some logs like:
/var/tmp/portage/www-client/firefox-98.0.2/work/firefox-98.0.2/security/sandbox/linux/reporter/SandboxReporter.cpp:35:4: error: #error "unrecognized architecture"
164:47.00 /var/tmp/portage/www-client/firefox-98.0.2/work/firefox-98.0.2/security/sandbox/chromium/sandbox/linux/system_headers/linux_signal.h:65:2: error: #error "Unsupported platform"
164:47.58 /var/tmp/portage/www-client/firefox-98.0.2/work/firefox-98.0.2/security/sandbox/chromium/sandbox/linux/bpf_dsl/seccomp_macros.h:350:2: error: #error Unsupported target platform

Closes: https://github.com/gentoo/riscv/pull/3
Signed-off-by: Yu Gu <guyu2876 <AT> gmail.com>
Signed-off-by: Yixun Lan <dlan <AT> gentoo.org>

 ...o-riscv64-support-and-zenithal-backported.patch | 47126 +++++++++++++++++++
 www-client/firefox/firefox-98.0.2.ebuild           |     4 +-
 2 files changed, 47129 insertions(+), 1 deletion(-)

diff --git a/www-client/firefox/files/makotokato-riscv64-support-and-zenithal-backported.patch b/www-client/firefox/files/makotokato-riscv64-support-and-zenithal-backported.patch
new file mode 100644
index 0000000..39ebd6a
--- /dev/null
+++ b/www-client/firefox/files/makotokato-riscv64-support-and-zenithal-backported.patch
@@ -0,0 +1,47126 @@
+From: Zenithal <i@zenithal.me>
+
+Some changes would be rejected/ignored when patching firefox 92 src,
+so I commented out some blocks, see these #-leading block below
+
+From be9cbd86b4c121dbdb626f8c373fd809f25bc23e Mon Sep 17 00:00:00 2001
+From: Makoto Kato <m_kato@ga2.so-net.ne.jp>
+Date: Sun, 13 Jun 2021 04:06:39 +0000
+Subject: [PATCH] Update authenticator-rs
+
+---
+ .cargo/config.in                              |    5 +
+ Cargo.lock                                    |    3 +-
+ .../rust/authenticator/.cargo-checksum.json   |    2 +-
+ third_party/rust/authenticator/.clippy.toml   |    2 +
+ third_party/rust/authenticator/.flake8        |    4 +
+ .../authenticator/.pre-commit-config.yaml     |   42 +
+ third_party/rust/authenticator/.travis.yml    |   42 +
+ third_party/rust/authenticator/Cargo.lock     | 1603 -----------------
+ third_party/rust/authenticator/Cargo.toml     |  131 +-
+ third_party/rust/authenticator/build.rs       |    2 +
+ .../authenticator/src/linux/hidwrapper.rs     |    3 +
+ .../authenticator/src/linux/ioctl_riscv64.rs  |    5 +
+ toolkit/library/rust/shared/Cargo.toml        |    2 +-
+ 13 files changed, 154 insertions(+), 1692 deletions(-)
+ create mode 100644 third_party/rust/authenticator/.clippy.toml
+ create mode 100644 third_party/rust/authenticator/.flake8
+ create mode 100644 third_party/rust/authenticator/.pre-commit-config.yaml
+ create mode 100644 third_party/rust/authenticator/.travis.yml
+ delete mode 100644 third_party/rust/authenticator/Cargo.lock
+ create mode 100644 third_party/rust/authenticator/src/linux/ioctl_riscv64.rs
+
+diff --unified --recursive --text a/.cargo/config.in b/.cargo/config.in
+--- a/.cargo/config.in  2022-03-10 14:19:43.020478706 +0800
++++ b/.cargo/config.in  2022-03-10 14:21:21.873044017 +0800
+@@ -22,11 +22,6 @@
+ replace-with = "vendored-sources"
+ rev = "3bfc47d9a571d0842676043ba60716318e946c06"
+ 
+-[source."https://github.com/mozilla/midir.git"]
+-git = "https://github.com/mozilla/midir.git"
+-replace-with = "vendored-sources"
+-rev = "4c11f0ffb5d6a10de4aff40a7b81218b33b94e6f"
+-
+ [source."https://github.com/mozilla/l10nregistry-rs.git"]
+ git = "https://github.com/mozilla/l10nregistry-rs.git"
+ replace-with = "vendored-sources"
+@@ -57,6 +52,16 @@
+ replace-with = "vendored-sources"
+ rev = "a1a6ba41f0c610ebe751639f25f037474ca52941"
+ 
++[source."https://github.com/makotokato/midir.git"]
++git = "https://github.com/makotokato/midir.git"
++replace-with = "vendored-sources"
++rev = "6140b2825dd4dc2b40e49e154ca7596e7b9a131a"
++
++[source."https://github.com/makotokato/authenticator-rs"]
++git = "https://github.com/makotokato/authenticator-rs"
++replace-with = "vendored-sources"
++rev = "eed8919d50559f4959e2d7d2af7b4d48869b5366"
++
+ [source."https://github.com/kinetiknz/mio-named-pipes"]
+ git = "https://github.com/kinetiknz/mio-named-pipes"
+ replace-with = "vendored-sources"
+diff --git a/Cargo.lock b/Cargo.lock
+index 7e17939fad48b..8519d3d0e95a6 100644
+--- a/Cargo.lock
++++ b/Cargo.lock
+@@ -316,8 +316,7 @@ dependencies = [
+ [[package]]
+ name = "authenticator"
+ version = "0.3.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-checksum = "08cee7a0952628fde958e149507c2bb321ab4fccfafd225da0b20adc956ef88a"
++source = "git+https://github.com/makotokato/authenticator-rs?rev=eed8919d50559f4959e2d7d2af7b4d48869b5366#eed8919d50559f4959e2d7d2af7b4d48869b5366"
+ dependencies = [
+  "bitflags",
+  "core-foundation",
+diff --git a/third_party/rust/authenticator/.cargo-checksum.json b/third_party/rust/authenticator/.cargo-checksum.json
+index ce451ad09df4f..9791345c9de54 100644
+--- a/third_party/rust/authenticator/.cargo-checksum.json
++++ b/third_party/rust/authenticator/.cargo-checksum.json
+@@ -1 +1 @@
+-{"files":{"Cargo.lock":"abaed4932db2206e5fdb7cb73a8c100f6c91fc84a8f33e8763677040ae8ea9bf","Cargo.toml":"9b56d5495021e7cd8ab7e019cceda45e906a2a3629a68e9019c6e5cb682dbc43","Cross.toml":"8d132da818d48492aa9f4b78a348f0df3adfae45d988d42ebd6be8a5adadb6c3","LICENSE":"e866c8f5864d4cacfe403820e722e9dc03fe3c7565efa5e4dad9051d827bb92a","README.md":"c87d9c7cc44f1dd4ef861a3a9f8cd2eb68aedd3814768871f5fb63c2070806cd","build.rs":"bc308b771ae9741d775370e3efe45e9cca166fd1d0335f4214b00497042ccc55","examples/main.rs":"d899646fa396776d0bb66efb86099ffb195566ecdb6fc4c1765ae3d54d696a8d","rustfmt.toml":"ceb6615363d6fff16426eb56f5727f98a7f7ed459ba9af735b1d8b672e2c3b9b","src/authenticatorservice.rs":"9fc5bcdd1e4f32e58ae920f96f40619a870b0a1b8d05db650803b2402a37fbf9","src/capi.rs":"1d3145ce81293bec697b0d385357fb1b0b495b0c356e2da5e6f15d028d328c70","src/consts.rs":"3dbcdfced6241822062e1aa2e6c8628af5f539ea18ee41edab51a3d33ebb77c6","src/errors.rs":"de89e57435ed1f9ff10f1f2d997a5b29d61cb215551e0ab40861a08ca52d1447",
 "src/freebsd/device.rs":"595df4b3f66b90dd73f8df67e1a2ba9a20c0b5fd893afbadbec564aa34f89981","src/freebsd/mod.rs":"42dcb57fbeb00140003a8ad39acac9b547062b8f281a3fa5deb5f92a6169dde6","src/freebsd/monitor.rs":"c10b154632fbedc3dca27197f7fc890c3d50ac1744b927e9f1e44a9e8a13506e","src/freebsd/transaction.rs":"bfb92dcf2edeb5d620a019907fff1025eb36ef322055e78649a3055b074fa851","src/freebsd/uhid.rs":"84f564d337637c1cd107ccc536b8fce2230628e144e4031e8db4d7163c9c0cb3","src/hidproto.rs":"362fc8e24b94ba431aad5ee0002f5a3364badd937c706c0ae119a5a7a2abc7c2","src/lib.rs":"12f62285a3d33347f95236b71341462a76ea1ded67651fc96ba25d7bd1dd8298","src/linux/device.rs":"d27c5f877cf96b97668579ac5db0f2685f7c969e7a5d0ddc68043eb16bfcddb8","src/linux/hidraw.rs":"ed55caa40fd518d67bb67d5af08f9adcab34f89e0ca591142d45b87f172926dd","src/linux/hidwrapper.h":"72785db3a9b27ea72b6cf13a958fee032af54304522d002f56322473978a20f9","src/linux/hidwrapper.rs":"4be65676cf3220929700bf4906938dcbd1538ba53d40c60b08f9ba8890c910f6","src/linux/io
 ctl_aarch64le.rs":"2d8b265cd39a9f46816f83d5a5df0701c13eb842bc609325bad42ce50add3bf0","src/linux/ioctl_armle.rs":"2d8b265cd39a9f46816f83d5a5df0701c13eb842bc609325bad42ce50add3bf0","src/linux/ioctl_mips64le.rs":"fbda309934ad8bda689cd4fb5c0ca696fe26dedb493fe9d5a5322c3047d474fd","src/linux/ioctl_mipsbe.rs":"fbda309934ad8bda689cd4fb5c0ca696fe26dedb493fe9d5a5322c3047d474fd","src/linux/ioctl_mipsle.rs":"fbda309934ad8bda689cd4fb5c0ca696fe26dedb493fe9d5a5322c3047d474fd","src/linux/ioctl_powerpc64be.rs":"fbda309934ad8bda689cd4fb5c0ca696fe26dedb493fe9d5a5322c3047d474fd","src/linux/ioctl_powerpc64le.rs":"fbda309934ad8bda689cd4fb5c0ca696fe26dedb493fe9d5a5322c3047d474fd","src/linux/ioctl_powerpcbe.rs":"fbda309934ad8bda689cd4fb5c0ca696fe26dedb493fe9d5a5322c3047d474fd","src/linux/ioctl_s390xbe.rs":"2d8b265cd39a9f46816f83d5a5df0701c13eb842bc609325bad42ce50add3bf0","src/linux/ioctl_x86.rs":"2d8b265cd39a9f46816f83d5a5df0701c13eb842bc609325bad42ce50add3bf0","src/linux/ioctl_x86_64.rs":"2d8b265cd39a9f46
 816f83d5a5df0701c13eb842bc609325bad42ce50add3bf0","src/linux/mod.rs":"446e435126d2a58f167f648dd95cba28e8ac9c17f1f799e1eaeab80ea800fc57","src/linux/monitor.rs":"9ef4e22fdcf005dd5201b42595d958ea462998c75dbfc68c8a403e7be64328e4","src/linux/transaction.rs":"bfb92dcf2edeb5d620a019907fff1025eb36ef322055e78649a3055b074fa851","src/macos/device.rs":"cc97b773254a89526164987e4b8e4181910fc3decb32acf51ca86c596ad0147b","src/macos/iokit.rs":"7dc4e7bbf8e42e2fcde0cee8e48d14d6234a5a910bd5d3c4e966d8ba6b73992f","src/macos/mod.rs":"333e561554fc901d4f6092f6e4c85823e2b0c4ff31c9188d0e6d542b71a0a07c","src/macos/monitor.rs":"d059861b4739c9272fa305b6dd91ebeb08530bd0e70a013dd999565d6f06fb30","src/macos/transaction.rs":"935b4bc79b0e50a984604a1ada96a7ef723cc283b7d33ca07f3150b1752b99f7","src/manager.rs":"5a4cdc26b9fde20e1a3dc2389f15d38d9153109bfee5119c092fbfdbd19bad8d","src/netbsd/device.rs":"3a99a989a7a8411ddb9893c371644076662a3b488d40b436601c27fd92fdf159","src/netbsd/fd.rs":"260f1a8ae04896c0eb35ab0914e11ca9291e
 7317a086c94328aa219c0e1fc1d2","src/netbsd/mod.rs":"b1c52aa29537330cebe67427062d6c94871cab2a9b0c04b2305d686f07e88fd5","src/netbsd/monitor.rs":"dfd68e026c52271b68a3a9263837c793127e9d54ed19b748ef6d13ab4c44e09a","src/netbsd/transaction.rs":"9334a832a57e717a981c13c364ed4ee80ce9798460fc6c8954723d2fcf20585a","src/netbsd/uhid.rs":"154a4587767f151e3f846cc0b79f615d5137de67afed84f19176f27ac9097908","src/openbsd/device.rs":"ae1c8de90bb515a12d571372a30322fadb5122bc69ab71caf154452caa8a644f","src/openbsd/mod.rs":"514274d414042ff84b3667a41a736e78581e22fda87ccc97c2bc05617e381a30","src/openbsd/monitor.rs":"5eb071dd3719ea305eac21ec20596463f63790f8cd1f908a59e3f9cb0b71b5ad","src/openbsd/transaction.rs":"2380c9430f4c95a1fefaaab729d8ece0d149674708d705a71dd5d2513d9e1a4c","src/statecallback.rs":"6b16f97176db1ae3fc3851fe8394e4ffc324bc6fe59313845ac3a88132fd52f1","src/statemachine.rs":"27e2655411ebc1077c200f0aa2ba429ca656fc7dd6f90e08b51492b59ec72e61","src/stub/device.rs":"5e378147e113e20160a45d395b717bd3deecb3
 27247c24b6735035f7d50861b7","src/stub/mod.rs":"6a7fec504a52d403b0241b18cd8b95088a31807571f4c0a67e4055afc74f4453","src/stub/transaction.rs":"4a2ccb2d72070a8bc61442254e063278c68212d5565ba5bfe4d47cacebf5bd1c","src/u2fhid-capi.h":"10f2658df774bb7f7f197a9f217b9e20d67b232b60a554e8ee3c3f71480ea1f6","src/u2fprotocol.rs":"72120773a948ffd667b5976c26ae27a4327769d97b0eef7a3b1e6b2b4bbb46a9","src/u2ftypes.rs":"a02d2c29790c5edfec9af320b1d4bcb93be0bbf02b881fa5aa403cfb687a25ae","src/util.rs":"d2042b2db4864f2b1192606c3251709361de7fb7521e1519190ef26a77de8e64","src/virtualdevices/mod.rs":"2c7df7691d5c150757304241351612aed4260d65b70ab0f483edbc1a5cfb5674","src/virtualdevices/software_u2f.rs":"1b86b94c6eadec6a22dffdd2b003c5324247c6412eeddb28a6094feb1c523f8e","src/virtualdevices/webdriver/mod.rs":"4a36e6dfa9f45f941d863b4039bfbcfa8eaca660bd6ed78aeb1a2962db64be5a","src/virtualdevices/webdriver/testtoken.rs":"7146e02f1a5dad2c8827dd11c12ee408c0e42a0706ac65f139998feffd42570f","src/virtualdevices/webdriver/virtu
 almanager.rs":"a55a28995c81b5affb0a74207b6dd556d272086a554676df2e675fe991d730a9","src/virtualdevices/webdriver/web_api.rs":"27206ee09c83fe25b34cad62174e42383defd8c8a5e917d30691412aacdae08f","src/windows/device.rs":"bc3f9587677c185a624c0aae7537baf9f780484ab8337929db994800b9064ba9","src/windows/mod.rs":"218e7f2fe91ecb390c12bba5a5ffdad2c1f0b22861c937f4d386262e5b3dd617","src/windows/monitor.rs":"3804dc67de46a1a6b7925c83e0df95d94ddfa1aa53a88fc845f4ff26aede57f8","src/windows/transaction.rs":"ee639f28b2dcdb7e00c922d8762fe6aa33def8c7aaeb46ec93e3a772407a9d86","src/windows/winapi.rs":"de92afb17df26216161138f18eb3b9162f3fb2cdeb74aa78173afe804ba02e00","testing/cross/powerpc64le-unknown-linux-gnu.Dockerfile":"d7463ff4376e3e0ca3fed879fab4aa975c4c0a3e7924c5b88aef9381a5d013de","testing/cross/x86_64-unknown-linux-gnu.Dockerfile":"11c79c04b07a171b0c9b63ef75fa75f33263ce76e3c1eda0879a3e723ebd0c24","testing/run_cross.sh":"cc2a7e0359f210eba2e7121f81eb8ab0125cea6e0d0f2698177b0fe2ad0c33d8","webdriver-tools
 /requirements.txt":"8236aa3dedad886f213c9b778fec80b037212d30e640b458984110211d546005","webdriver-tools/webdriver-driver.py":"82327c26ba271d1689acc87b612ab8436cb5475f0a3c0dba7baa06e7f6f5e19c"},"package":"08cee7a0952628fde958e149507c2bb321ab4fccfafd225da0b20adc956ef88a"}
+\ No newline at end of file
++{"files":{".clippy.toml":"86011295a6e2cea043b8002238f9c96b39f17aa8241aa079f44bb6e71eb62421",".flake8":"04f55f4a3c02b50dfa568ce4f7c6a47a9374b6483256811f8be702d1382576cd",".pre-commit-config.yaml":"b7920a17d5a378c7702f9c39bf5156bb8c4ea15d8691217e0a5a8e8f571b4cf7",".travis.yml":"883be088379477e7fa6f3d06b1c8d59dc41da61b6c15d2675c62113341e7b2d5","Cargo.toml":"e7334212220a6d8ca01996888275cc0d11d098e36db1bf4c5b7429051897bf3f","Cross.toml":"8d132da818d48492aa9f4b78a348f0df3adfae45d988d42ebd6be8a5adadb6c3","LICENSE":"e866c8f5864d4cacfe403820e722e9dc03fe3c7565efa5e4dad9051d827bb92a","README.md":"c87d9c7cc44f1dd4ef861a3a9f8cd2eb68aedd3814768871f5fb63c2070806cd","build.rs":"a459ee1ace052f9692817b15c702cb6e5a6dac7c7dfe74fa075662dbcf808dbe","examples/main.rs":"d899646fa396776d0bb66efb86099ffb195566ecdb6fc4c1765ae3d54d696a8d","rustfmt.toml":"ceb6615363d6fff16426eb56f5727f98a7f7ed459ba9af735b1d8b672e2c3b9b","src/authenticatorservice.rs":"9fc5bcdd1e4f32e58ae920f96f40619a870b0a1b8d05db650803b2402a37
 fbf9","src/capi.rs":"1d3145ce81293bec697b0d385357fb1b0b495b0c356e2da5e6f15d028d328c70","src/consts.rs":"3dbcdfced6241822062e1aa2e6c8628af5f539ea18ee41edab51a3d33ebb77c6","src/errors.rs":"de89e57435ed1f9ff10f1f2d997a5b29d61cb215551e0ab40861a08ca52d1447","src/freebsd/device.rs":"595df4b3f66b90dd73f8df67e1a2ba9a20c0b5fd893afbadbec564aa34f89981","src/freebsd/mod.rs":"42dcb57fbeb00140003a8ad39acac9b547062b8f281a3fa5deb5f92a6169dde6","src/freebsd/monitor.rs":"c10b154632fbedc3dca27197f7fc890c3d50ac1744b927e9f1e44a9e8a13506e","src/freebsd/transaction.rs":"bfb92dcf2edeb5d620a019907fff1025eb36ef322055e78649a3055b074fa851","src/freebsd/uhid.rs":"84f564d337637c1cd107ccc536b8fce2230628e144e4031e8db4d7163c9c0cb3","src/hidproto.rs":"362fc8e24b94ba431aad5ee0002f5a3364badd937c706c0ae119a5a7a2abc7c2","src/lib.rs":"12f62285a3d33347f95236b71341462a76ea1ded67651fc96ba25d7bd1dd8298","src/linux/device.rs":"d27c5f877cf96b97668579ac5db0f2685f7c969e7a5d0ddc68043eb16bfcddb8","src/linux/hidraw.rs":"ed55caa40fd
 518d67bb67d5af08f9adcab34f89e0ca591142d45b87f172926dd","src/linux/hidwrapper.h":"72785db3a9b27ea72b6cf13a958fee032af54304522d002f56322473978a20f9","src/linux/hidwrapper.rs":"753c7459dbb73befdd186b6269ac33f7a4537b4c935928f50f2b2131756e787d","src/linux/ioctl_aarch64le.rs":"2d8b265cd39a9f46816f83d5a5df0701c13eb842bc609325bad42ce50add3bf0","src/linux/ioctl_armle.rs":"2d8b265cd39a9f46816f83d5a5df0701c13eb842bc609325bad42ce50add3bf0","src/linux/ioctl_mips64le.rs":"fbda309934ad8bda689cd4fb5c0ca696fe26dedb493fe9d5a5322c3047d474fd","src/linux/ioctl_mipsbe.rs":"fbda309934ad8bda689cd4fb5c0ca696fe26dedb493fe9d5a5322c3047d474fd","src/linux/ioctl_mipsle.rs":"fbda309934ad8bda689cd4fb5c0ca696fe26dedb493fe9d5a5322c3047d474fd","src/linux/ioctl_powerpc64be.rs":"fbda309934ad8bda689cd4fb5c0ca696fe26dedb493fe9d5a5322c3047d474fd","src/linux/ioctl_powerpc64le.rs":"fbda309934ad8bda689cd4fb5c0ca696fe26dedb493fe9d5a5322c3047d474fd","src/linux/ioctl_powerpcbe.rs":"fbda309934ad8bda689cd4fb5c0ca696fe26dedb493fe9
 d5a5322c3047d474fd","src/linux/ioctl_riscv64.rs":"2d8b265cd39a9f46816f83d5a5df0701c13eb842bc609325bad42ce50add3bf0","src/linux/ioctl_s390xbe.rs":"2d8b265cd39a9f46816f83d5a5df0701c13eb842bc609325bad42ce50add3bf0","src/linux/ioctl_x86.rs":"2d8b265cd39a9f46816f83d5a5df0701c13eb842bc609325bad42ce50add3bf0","src/linux/ioctl_x86_64.rs":"2d8b265cd39a9f46816f83d5a5df0701c13eb842bc609325bad42ce50add3bf0","src/linux/mod.rs":"446e435126d2a58f167f648dd95cba28e8ac9c17f1f799e1eaeab80ea800fc57","src/linux/monitor.rs":"9ef4e22fdcf005dd5201b42595d958ea462998c75dbfc68c8a403e7be64328e4","src/linux/transaction.rs":"bfb92dcf2edeb5d620a019907fff1025eb36ef322055e78649a3055b074fa851","src/macos/device.rs":"cc97b773254a89526164987e4b8e4181910fc3decb32acf51ca86c596ad0147b","src/macos/iokit.rs":"7dc4e7bbf8e42e2fcde0cee8e48d14d6234a5a910bd5d3c4e966d8ba6b73992f","src/macos/mod.rs":"333e561554fc901d4f6092f6e4c85823e2b0c4ff31c9188d0e6d542b71a0a07c","src/macos/monitor.rs":"d059861b4739c9272fa305b6dd91ebeb08530bd0e
 70a013dd999565d6f06fb30","src/macos/transaction.rs":"935b4bc79b0e50a984604a1ada96a7ef723cc283b7d33ca07f3150b1752b99f7","src/manager.rs":"5a4cdc26b9fde20e1a3dc2389f15d38d9153109bfee5119c092fbfdbd19bad8d","src/netbsd/device.rs":"3a99a989a7a8411ddb9893c371644076662a3b488d40b436601c27fd92fdf159","src/netbsd/fd.rs":"260f1a8ae04896c0eb35ab0914e11ca9291e7317a086c94328aa219c0e1fc1d2","src/netbsd/mod.rs":"b1c52aa29537330cebe67427062d6c94871cab2a9b0c04b2305d686f07e88fd5","src/netbsd/monitor.rs":"dfd68e026c52271b68a3a9263837c793127e9d54ed19b748ef6d13ab4c44e09a","src/netbsd/transaction.rs":"9334a832a57e717a981c13c364ed4ee80ce9798460fc6c8954723d2fcf20585a","src/netbsd/uhid.rs":"154a4587767f151e3f846cc0b79f615d5137de67afed84f19176f27ac9097908","src/openbsd/device.rs":"ae1c8de90bb515a12d571372a30322fadb5122bc69ab71caf154452caa8a644f","src/openbsd/mod.rs":"514274d414042ff84b3667a41a736e78581e22fda87ccc97c2bc05617e381a30","src/openbsd/monitor.rs":"5eb071dd3719ea305eac21ec20596463f63790f8cd1f908a59e3
 f9cb0b71b5ad","src/openbsd/transaction.rs":"2380c9430f4c95a1fefaaab729d8ece0d149674708d705a71dd5d2513d9e1a4c","src/statecallback.rs":"6b16f97176db1ae3fc3851fe8394e4ffc324bc6fe59313845ac3a88132fd52f1","src/statemachine.rs":"27e2655411ebc1077c200f0aa2ba429ca656fc7dd6f90e08b51492b59ec72e61","src/stub/device.rs":"5e378147e113e20160a45d395b717bd3deecb327247c24b6735035f7d50861b7","src/stub/mod.rs":"6a7fec504a52d403b0241b18cd8b95088a31807571f4c0a67e4055afc74f4453","src/stub/transaction.rs":"4a2ccb2d72070a8bc61442254e063278c68212d5565ba5bfe4d47cacebf5bd1c","src/u2fhid-capi.h":"10f2658df774bb7f7f197a9f217b9e20d67b232b60a554e8ee3c3f71480ea1f6","src/u2fprotocol.rs":"72120773a948ffd667b5976c26ae27a4327769d97b0eef7a3b1e6b2b4bbb46a9","src/u2ftypes.rs":"a02d2c29790c5edfec9af320b1d4bcb93be0bbf02b881fa5aa403cfb687a25ae","src/util.rs":"d2042b2db4864f2b1192606c3251709361de7fb7521e1519190ef26a77de8e64","src/virtualdevices/mod.rs":"2c7df7691d5c150757304241351612aed4260d65b70ab0f483edbc1a5cfb5674","src/v
 irtualdevices/software_u2f.rs":"1b86b94c6eadec6a22dffdd2b003c5324247c6412eeddb28a6094feb1c523f8e","src/virtualdevices/webdriver/mod.rs":"4a36e6dfa9f45f941d863b4039bfbcfa8eaca660bd6ed78aeb1a2962db64be5a","src/virtualdevices/webdriver/testtoken.rs":"7146e02f1a5dad2c8827dd11c12ee408c0e42a0706ac65f139998feffd42570f","src/virtualdevices/webdriver/virtualmanager.rs":"a55a28995c81b5affb0a74207b6dd556d272086a554676df2e675fe991d730a9","src/virtualdevices/webdriver/web_api.rs":"27206ee09c83fe25b34cad62174e42383defd8c8a5e917d30691412aacdae08f","src/windows/device.rs":"bc3f9587677c185a624c0aae7537baf9f780484ab8337929db994800b9064ba9","src/windows/mod.rs":"218e7f2fe91ecb390c12bba5a5ffdad2c1f0b22861c937f4d386262e5b3dd617","src/windows/monitor.rs":"3804dc67de46a1a6b7925c83e0df95d94ddfa1aa53a88fc845f4ff26aede57f8","src/windows/transaction.rs":"ee639f28b2dcdb7e00c922d8762fe6aa33def8c7aaeb46ec93e3a772407a9d86","src/windows/winapi.rs":"de92afb17df26216161138f18eb3b9162f3fb2cdeb74aa78173afe804ba02e00",
 "testing/cross/powerpc64le-unknown-linux-gnu.Dockerfile":"d7463ff4376e3e0ca3fed879fab4aa975c4c0a3e7924c5b88aef9381a5d013de","testing/cross/x86_64-unknown-linux-gnu.Dockerfile":"11c79c04b07a171b0c9b63ef75fa75f33263ce76e3c1eda0879a3e723ebd0c24","testing/run_cross.sh":"cc2a7e0359f210eba2e7121f81eb8ab0125cea6e0d0f2698177b0fe2ad0c33d8","webdriver-tools/requirements.txt":"8236aa3dedad886f213c9b778fec80b037212d30e640b458984110211d546005","webdriver-tools/webdriver-driver.py":"82327c26ba271d1689acc87b612ab8436cb5475f0a3c0dba7baa06e7f6f5e19c"},"package":null}
+\ No newline at end of file
+diff --git a/third_party/rust/authenticator/.clippy.toml b/third_party/rust/authenticator/.clippy.toml
+new file mode 100644
+index 0000000000000..844d0757e91f4
+--- /dev/null
++++ b/third_party/rust/authenticator/.clippy.toml
+@@ -0,0 +1,2 @@
++type-complexity-threshold = 384
++too-many-arguments-threshold = 8
+diff --git a/third_party/rust/authenticator/.flake8 b/third_party/rust/authenticator/.flake8
+new file mode 100644
+index 0000000000000..5a725c9b4ce65
+--- /dev/null
++++ b/third_party/rust/authenticator/.flake8
+@@ -0,0 +1,4 @@
++[flake8]
++# See http://pep8.readthedocs.io/en/latest/intro.html#configuration
++ignore = E121, E123, E126, E129, E133, E203, E226, E241, E242, E704, W503, E402, E741
++max-line-length = 99
+diff --git a/third_party/rust/authenticator/.pre-commit-config.yaml b/third_party/rust/authenticator/.pre-commit-config.yaml
+new file mode 100644
+index 0000000000000..e0ceb8ea5473c
+--- /dev/null
++++ b/third_party/rust/authenticator/.pre-commit-config.yaml
+@@ -0,0 +1,42 @@
++- repo: git://github.com/pre-commit/pre-commit-hooks
++  rev: HEAD
++  hooks:
++    - id: flake8
++    - id: check-ast
++    - id: detect-private-key
++    - id: detect-aws-credentials
++    - id: check-merge-conflict
++    - id: end-of-file-fixer
++    - id: requirements-txt-fixer
++    - id: trailing-whitespace
++- repo: local
++  hooks:
++    - id: rustfmt
++      name: Check rustfmt
++      language: system
++      entry: cargo fmt -- --check
++      pass_filenames: false
++      files: '.rs$'
++- repo: local
++  hooks:
++    - id: tests
++      name: Run tests
++      language: system
++      entry: cargo test --all-targets --all-features
++      pass_filenames: false
++      files: '.rs$'
++- repo: local
++  hooks:
++    - id: clippy
++      name: Check clippy
++      language: system
++      entry: cargo clippy --all-targets -- -A renamed_and_removed_lints -A clippy::new-ret-no-self -D warnings
++      pass_filenames: false
++      files: '.rs$'
++- repo: local
++  hooks:
++    - id: black
++      name: Check black
++      language: system
++      entry: black
++      files: '.py$'
+diff --git a/third_party/rust/authenticator/.travis.yml b/third_party/rust/authenticator/.travis.yml
+new file mode 100644
+index 0000000000000..70ea5c5581af2
+--- /dev/null
++++ b/third_party/rust/authenticator/.travis.yml
+@@ -0,0 +1,42 @@
++os:
++  - linux
++  - windows
++
++language: rust
++rust:
++  - stable
++  - nightly
++cache: cargo
++
++jobs:
++  allow_failures:
++    - rust: nightly
++
++addons:
++  apt:
++    packages:
++      - build-essential
++      - libudev-dev
++
++install:
++  - rustup component add rustfmt
++  - rustup component add clippy
++
++script:
++- |
++  if [ "$TRAVIS_RUST_VERSION" == "nightly" ] && [ "$TRAVIS_OS_NAME" == "linux" ] ; then
++    export ASAN_OPTIONS="detect_odr_violation=1:leak_check_at_exit=0:detect_leaks=0"
++    export RUSTFLAGS="-Z sanitizer=address"
++  fi
++- |
++  if [ "$TRAVIS_RUST_VERSION" == "stable" ] && [ "$TRAVIS_OS_NAME" == "linux" ] ; then
++    echo "Running rustfmt"
++    cargo fmt --all -- --check
++    echo "Running clippy"
++    cargo clippy --all-targets --all-features -- -A renamed_and_removed_lints -A clippy::new-ret-no-self -D warnings
++
++    rustup install nightly
++    cargo install cargo-fuzz
++    cargo +nightly fuzz build
++  fi
++- cargo test --all-targets --all-features
+diff --git a/third_party/rust/authenticator/Cargo.lock b/third_party/rust/authenticator/Cargo.lock
+deleted file mode 100644
+index 9f284b468deaa..0000000000000
+--- a/third_party/rust/authenticator/Cargo.lock
++++ /dev/null
+@@ -1,1603 +0,0 @@
+-# This file is automatically @generated by Cargo.
+-# It is not intended for manual editing.
+-[[package]]
+-name = "aho-corasick"
+-version = "0.7.13"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "ansi_term"
+-version = "0.11.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "assert_matches"
+-version = "1.3.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "atty"
+-version = "0.2.14"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
+- "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
+- "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "authenticator"
+-version = "0.3.1"
+-dependencies = [
+- "assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "bytes 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+- "core-foundation 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "devd-rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+- "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
+- "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
+- "libudev 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
+- "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
+- "runloop 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "serde 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)",
+- "serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)",
+- "sha2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
+- "tokio 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
+- "warp 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "autocfg"
+-version = "0.1.7"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "autocfg"
+-version = "1.0.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "base64"
+-version = "0.10.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "base64"
+-version = "0.12.3"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "bindgen"
+-version = "0.51.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "cexpr 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+- "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+- "clang-sys 0.28.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+- "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
+- "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+- "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
+- "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
+- "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+- "rustc-hash 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "which 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "bitflags"
+-version = "1.2.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "block-buffer"
+-version = "0.7.3"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+- "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "block-buffer"
+-version = "0.9.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "generic-array 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "block-padding"
+-version = "0.1.5"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "buf_redux"
+-version = "0.8.4"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+- "safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "byte-tools"
+-version = "0.3.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "byteorder"
+-version = "1.3.4"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "bytes"
+-version = "0.5.6"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "serde 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "cc"
+-version = "1.0.58"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "cexpr"
+-version = "0.3.6"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "cfg-if"
+-version = "0.1.10"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "clang-sys"
+-version = "0.28.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
+- "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "clap"
+-version = "2.33.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
+- "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+- "vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "cloudabi"
+-version = "0.0.3"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "core-foundation"
+-version = "0.9.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "core-foundation-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "core-foundation-sys"
+-version = "0.8.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "cpuid-bool"
+-version = "0.1.2"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "devd-rs"
+-version = "0.3.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
+- "nom 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "digest"
+-version = "0.8.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "digest"
+-version = "0.9.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "generic-array 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "dtoa"
+-version = "0.4.6"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "env_logger"
+-version = "0.6.2"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
+- "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
+- "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+- "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "fake-simd"
+-version = "0.1.2"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "fnv"
+-version = "1.0.7"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "fuchsia-cprng"
+-version = "0.1.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "fuchsia-zircon"
+-version = "0.3.3"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "fuchsia-zircon-sys"
+-version = "0.3.3"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "futures"
+-version = "0.3.5"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "futures-channel"
+-version = "0.3.5"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "futures-core"
+-version = "0.3.5"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "futures-io"
+-version = "0.3.5"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "futures-sink"
+-version = "0.3.5"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "futures-task"
+-version = "0.3.5"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "once_cell 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "futures-util"
+-version = "0.3.5"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "pin-project 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)",
+- "pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "generic-array"
+-version = "0.12.3"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "generic-array"
+-version = "0.14.4"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "getopts"
+-version = "0.2.21"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "getrandom"
+-version = "0.1.14"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+- "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
+- "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "glob"
+-version = "0.3.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "h2"
+-version = "0.2.6"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "bytes 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+- "fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
+- "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "http 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "indexmap 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+- "tokio 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
+- "tokio-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "tracing 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "hashbrown"
+-version = "0.9.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "headers"
+-version = "0.3.2"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "base64 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
+- "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "bytes 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+- "headers-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "http 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
+- "sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
+- "time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "headers-core"
+-version = "0.2.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "http 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "hermit-abi"
+-version = "0.1.15"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "http"
+-version = "0.2.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "bytes 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+- "fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
+- "itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "http-body"
+-version = "0.3.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "bytes 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+- "http 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "httparse"
+-version = "1.3.4"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "humantime"
+-version = "1.3.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "hyper"
+-version = "0.13.7"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "bytes 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+- "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "h2 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+- "http 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "http-body 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+- "itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+- "pin-project 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)",
+- "socket2 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+- "time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)",
+- "tokio 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
+- "tower-service 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "tracing 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
+- "want 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "idna"
+-version = "0.2.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+- "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+- "unicode-normalization 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "indexmap"
+-version = "1.6.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "hashbrown 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "input_buffer"
+-version = "0.3.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "bytes 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "iovec"
+-version = "0.1.4"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "itoa"
+-version = "0.4.6"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "kernel32-sys"
+-version = "0.2.2"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+- "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "lazy_static"
+-version = "1.4.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "libc"
+-version = "0.2.73"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "libloading"
+-version = "0.5.2"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "cc 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)",
+- "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "libudev"
+-version = "0.2.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
+- "libudev-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "libudev-sys"
+-version = "0.1.4"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
+- "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "log"
+-version = "0.4.11"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "matches"
+-version = "0.1.8"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "memchr"
+-version = "2.3.3"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "mime"
+-version = "0.3.16"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "mime_guess"
+-version = "2.0.3"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
+- "unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "mio"
+-version = "0.6.22"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+- "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+- "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+- "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+- "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+- "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
+- "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
+- "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "net2 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
+- "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "miow"
+-version = "0.2.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+- "net2 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
+- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+- "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "multipart"
+-version = "0.17.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "buf_redux 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
+- "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+- "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
+- "mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
+- "mime_guess 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+- "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+- "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+- "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "twoway 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "net2"
+-version = "0.2.35"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+- "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
+- "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "nom"
+-version = "4.2.3"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+- "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "nom"
+-version = "5.1.2"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+- "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "once_cell"
+-version = "1.4.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "opaque-debug"
+-version = "0.2.3"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "opaque-debug"
+-version = "0.3.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "peeking_take_while"
+-version = "0.1.2"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "percent-encoding"
+-version = "2.1.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "pin-project"
+-version = "0.4.23"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "pin-project-internal 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "pin-project-internal"
+-version = "0.4.23"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
+- "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
+- "syn 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "pin-project-lite"
+-version = "0.1.7"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "pin-utils"
+-version = "0.1.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "pkg-config"
+-version = "0.3.18"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "ppv-lite86"
+-version = "0.2.8"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "proc-macro2"
+-version = "1.0.19"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "quick-error"
+-version = "1.2.3"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "quote"
+-version = "1.0.7"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "rand"
+-version = "0.6.5"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+- "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
+- "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+- "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+- "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+- "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+- "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "rand"
+-version = "0.7.3"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
+- "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
+- "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+- "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "rand_chacha"
+-version = "0.1.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+- "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "rand_chacha"
+-version = "0.2.2"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+- "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "rand_core"
+-version = "0.3.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "rand_core"
+-version = "0.4.2"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "rand_core"
+-version = "0.5.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "rand_hc"
+-version = "0.1.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "rand_hc"
+-version = "0.2.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "rand_isaac"
+-version = "0.1.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "rand_jitter"
+-version = "0.1.4"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
+- "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+- "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "rand_os"
+-version = "0.1.3"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+- "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
+- "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+- "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "rand_pcg"
+-version = "0.1.2"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+- "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "rand_xorshift"
+-version = "0.1.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "rdrand"
+-version = "0.4.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "redox_syscall"
+-version = "0.1.57"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "regex"
+-version = "1.3.9"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)",
+- "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+- "regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)",
+- "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "regex-syntax"
+-version = "0.6.18"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "remove_dir_all"
+-version = "0.5.3"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "runloop"
+-version = "0.1.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "rustc-hash"
+-version = "1.1.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "ryu"
+-version = "1.0.5"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "safemem"
+-version = "0.3.3"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "scoped-tls"
+-version = "1.0.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "serde"
+-version = "1.0.116"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "serde_derive 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "serde_derive"
+-version = "1.0.116"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
+- "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
+- "syn 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "serde_json"
+-version = "1.0.57"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+- "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "serde 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "serde_urlencoded"
+-version = "0.6.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "dtoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+- "itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+- "serde 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)",
+- "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "sha-1"
+-version = "0.8.2"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
+- "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+- "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "sha-1"
+-version = "0.9.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "block-buffer 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+- "cpuid-bool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+- "digest 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "opaque-debug 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "sha2"
+-version = "0.8.2"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
+- "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+- "opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "shlex"
+-version = "0.1.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "slab"
+-version = "0.4.2"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "socket2"
+-version = "0.3.15"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+- "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
+- "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)",
+- "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "strsim"
+-version = "0.8.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "syn"
+-version = "1.0.41"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
+- "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
+- "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "tempfile"
+-version = "3.1.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+- "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
+- "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
+- "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)",
+- "remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
+- "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "termcolor"
+-version = "1.1.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "textwrap"
+-version = "0.11.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "thread_local"
+-version = "1.0.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "time"
+-version = "0.1.44"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
+- "wasi 0.10.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "tinyvec"
+-version = "0.3.4"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "tokio"
+-version = "0.2.22"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "bytes 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+- "fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
+- "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+- "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+- "mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)",
+- "pin-project-lite 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+- "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+- "tokio-macros 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "tokio-macros"
+-version = "0.2.5"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)",
+- "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
+- "syn 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "tokio-tungstenite"
+-version = "0.11.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
+- "pin-project 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)",
+- "tokio 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
+- "tungstenite 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "tokio-util"
+-version = "0.3.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "bytes 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+- "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
+- "pin-project-lite 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+- "tokio 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "tower-service"
+-version = "0.3.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "tracing"
+-version = "0.1.19"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+- "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
+- "tracing-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "tracing-core"
+-version = "0.1.16"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "tracing-futures"
+-version = "0.2.4"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "pin-project 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)",
+- "tracing 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "try-lock"
+-version = "0.2.3"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "tungstenite"
+-version = "0.11.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "base64 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
+- "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+- "bytes 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+- "http 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+- "input_buffer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
+- "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
+- "sha-1 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "utf-8 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "twoway"
+-version = "0.1.8"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "typenum"
+-version = "1.12.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "unicase"
+-version = "2.6.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "unicode-bidi"
+-version = "0.3.4"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "unicode-normalization"
+-version = "0.1.13"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "tinyvec 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "unicode-width"
+-version = "0.1.8"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "unicode-xid"
+-version = "0.2.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "url"
+-version = "2.1.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+- "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "urlencoding"
+-version = "1.1.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "utf-8"
+-version = "0.7.5"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "vec_map"
+-version = "0.8.2"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "version_check"
+-version = "0.1.5"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "version_check"
+-version = "0.9.2"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "want"
+-version = "0.3.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
+- "try-lock 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "warp"
+-version = "0.2.5"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "bytes 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+- "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+- "headers 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+- "http 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "hyper 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)",
+- "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
+- "mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
+- "mime_guess 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+- "multipart 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "pin-project 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)",
+- "scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "serde 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)",
+- "serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)",
+- "serde_urlencoded 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
+- "tokio 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)",
+- "tokio-tungstenite 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "tower-service 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "tracing 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)",
+- "tracing-futures 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+- "urlencoding 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "wasi"
+-version = "0.9.0+wasi-snapshot-preview1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "wasi"
+-version = "0.10.0+wasi-snapshot-preview1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "which"
+-version = "3.1.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "winapi"
+-version = "0.2.8"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "winapi"
+-version = "0.3.9"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+- "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "winapi-build"
+-version = "0.1.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "winapi-i686-pc-windows-gnu"
+-version = "0.4.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "winapi-util"
+-version = "0.1.5"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[[package]]
+-name = "winapi-x86_64-pc-windows-gnu"
+-version = "0.4.0"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-
+-[[package]]
+-name = "ws2_32-sys"
+-version = "0.2.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-dependencies = [
+- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+- "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+-]
+-
+-[metadata]
+-"checksum aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)" = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86"
+-"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+-"checksum assert_matches 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7deb0a829ca7bcfaf5da70b073a8d128619259a7be8216a355e23f00763059e5"
+-"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+-"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
+-"checksum autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+-"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
+-"checksum base64 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
+-"checksum bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebd71393f1ec0509b553aa012b9b58e81dadbdff7130bd3b8cba576e69b32f75"
+-"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+-"checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"
+-"checksum block-buffer 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
+-"checksum block-padding 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5"
+-"checksum buf_redux 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f"
+-"checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
+-"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
+-"checksum bytes 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38"
+-"checksum cc 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)" = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518"
+-"checksum cexpr 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fce5b5fb86b0c57c20c834c1b412fd09c77c8a59b9473f86272709e78874cd1d"
+-"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+-"checksum clang-sys 0.28.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81de550971c976f176130da4b2978d3b524eaa0fd9ac31f3ceb5ae1231fb4853"
+-"checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129"
+-"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
+-"checksum core-foundation 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b5ed8e7e76c45974e15e41bfa8d5b0483cd90191639e01d8f5f1e606299d3fb"
+-"checksum core-foundation-sys 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9a21fa21941700a3cd8fcb4091f361a6a712fac632f85d9f487cc892045d55c6"
+-"checksum cpuid-bool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"
+-"checksum devd-rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1945ccb7caedabdfb9347766ead740fb1e0582b7425598325f546adbd832cce1"
+-"checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"
+-"checksum digest 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
+-"checksum dtoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b"
+-"checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
+-"checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
+-"checksum fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+-"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
+-"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
+-"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
+-"checksum futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613"
+-"checksum futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5"
+-"checksum futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399"
+-"checksum futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789"
+-"checksum futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc"
+-"checksum futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626"
+-"checksum futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6"
+-"checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"
+-"checksum generic-array 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
+-"checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
+-"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
+-"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
+-"checksum h2 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "993f9e0baeed60001cf565546b0d3dbe6a6ad23f2bd31644a133c641eccf6d53"
+-"checksum hashbrown 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "00d63df3d41950fb462ed38308eea019113ad1508da725bbedcd0fa5a85ef5f7"
+-"checksum headers 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ed18eb2459bf1a09ad2d6b1547840c3e5e62882fa09b9a6a20b1de8e3228848f"
+-"checksum headers-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429"
+-"checksum hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9"
+-"checksum http 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "28d569972648b2c512421b5f2a405ad6ac9666547189d0c5477a3f200f3e02f9"
+-"checksum http-body 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b"
+-"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9"
+-"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
+-"checksum hyper 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3e68a8dd9716185d9e64ea473ea6ef63529252e3e27623295a0378a19665d5eb"
+-"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
+-"checksum indexmap 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2"
+-"checksum input_buffer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "19a8a95243d5a0398cae618ec29477c6e3cb631152be5c19481f80bc71559754"
+-"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
+-"checksum itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
+-"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
+-"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+-"checksum libc 0.2.73 (registry+https://github.com/rust-lang/crates.io-index)" = "bd7d4bd64732af4bf3a67f367c27df8520ad7e230c5817b8ff485864d80242b9"
+-"checksum libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753"
+-"checksum libudev 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea626d3bdf40a1c5aee3bcd4f40826970cae8d80a8fec934c82a63840094dcfe"
+-"checksum libudev-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324"
+-"checksum log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
+-"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
+-"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
+-"checksum mime 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
+-"checksum mime_guess 2.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2684d4c2e97d99848d30b324b00c8fcc7e5c897b7cbb5819b09e7c90e8baf212"
+-"checksum mio 0.6.22 (registry+https://github.com/rust-lang/crates.io-index)" = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430"
+-"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
+-"checksum multipart 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8209c33c951f07387a8497841122fc6f712165e3f9bda3e6be4645b58188f676"
+-"checksum net2 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)" = "3ebc3ec692ed7c9a255596c67808dee269f64655d8baf7b4f0638e51ba1d6853"
+-"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
+-"checksum nom 5.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
+-"checksum once_cell 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad"
+-"checksum opaque-debug 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
+-"checksum opaque-debug 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
+-"checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
+-"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
+-"checksum pin-project 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)" = "ca4433fff2ae79342e497d9f8ee990d174071408f28f726d6d83af93e58e48aa"
+-"checksum pin-project-internal 0.4.23 (registry+https://github.com/rust-lang/crates.io-index)" = "2c0e815c3ee9a031fdf5af21c10aa17c573c9c6a566328d99e3936c34e36461f"
+-"checksum pin-project-lite 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "282adbf10f2698a7a77f8e983a74b2d18176c19a7fd32a45446139ae7b02b715"
+-"checksum pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+-"checksum pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33"
+-"checksum ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea"
+-"checksum proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12"
+-"checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
+-"checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
+-"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
+-"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
+-"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
+-"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
+-"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
+-"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
+-"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
+-"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
+-"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
+-"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
+-"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
+-"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
+-"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
+-"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
+-"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
+-"checksum redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)" = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
+-"checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
+-"checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
+-"checksum remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
+-"checksum runloop 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d79b4b604167921892e84afbbaad9d5ad74e091bf6c511d9dbfb0593f09fabd"
+-"checksum rustc-hash 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+-"checksum ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
+-"checksum safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
+-"checksum scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
+-"checksum serde 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)" = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5"
+-"checksum serde_derive 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)" = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8"
+-"checksum serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)" = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c"
+-"checksum serde_urlencoded 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97"
+-"checksum sha-1 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df"
+-"checksum sha-1 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "170a36ea86c864a3f16dd2687712dd6646f7019f301e57537c7f4dc9f5916770"
+-"checksum sha2 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69"
+-"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
+-"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
+-"checksum socket2 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "b1fa70dc5c8104ec096f4fe7ede7a221d35ae13dcd19ba1ad9a81d2cab9a1c44"
+-"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
+-"checksum syn 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b"
+-"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
+-"checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
+-"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+-"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
+-"checksum time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
+-"checksum tinyvec 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "238ce071d267c5710f9d31451efec16c5ee22de34df17cc05e56cbc92e967117"
+-"checksum tokio 0.2.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5d34ca54d84bf2b5b4d7d31e901a8464f7b60ac145a284fba25ceb801f2ddccd"
+-"checksum tokio-macros 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389"
+-"checksum tokio-tungstenite 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d9e878ad426ca286e4dcae09cbd4e1973a7f8987d97570e2469703dd7f5720c"
+-"checksum tokio-util 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499"
+-"checksum tower-service 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860"
+-"checksum tracing 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6d79ca061b032d6ce30c660fded31189ca0b9922bf483cd70759f13a2d86786c"
+-"checksum tracing-core 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "5bcf46c1f1f06aeea2d6b81f3c863d0930a596c86ad1920d4e5bad6dd1d7119a"
+-"checksum tracing-futures 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ab7bb6f14721aa00656086e9335d363c5c8747bae02ebe32ea2c7dece5689b4c"
+-"checksum try-lock 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
+-"checksum tungstenite 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f0308d80d86700c5878b9ef6321f020f29b1bb9d5ff3cab25e75e23f3a492a23"
+-"checksum twoway 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1"
+-"checksum typenum 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
+-"checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
+-"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
+-"checksum unicode-normalization 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977"
+-"checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
+-"checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
+-"checksum url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb"
+-"checksum urlencoding 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c9232eb53352b4442e40d7900465dfc534e8cb2dc8f18656fcb2ac16112b5593"
+-"checksum utf-8 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7"
+-"checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
+-"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
+-"checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
+-"checksum want 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
+-"checksum warp 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f41be6df54c97904af01aa23e613d4521eed7ab23537cede692d4058f6449407"
+-"checksum wasi 0.10.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
+-"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
+-"checksum which 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724"
+-"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
+-"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+-"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
+-"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+-"checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+-"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+-"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
+diff --git a/third_party/rust/authenticator/Cargo.toml b/third_party/rust/authenticator/Cargo.toml
+index 57d24bd66b948..c49befae2178c 100644
+--- a/third_party/rust/authenticator/Cargo.toml
++++ b/third_party/rust/authenticator/Cargo.toml
+@@ -1,99 +1,60 @@
+-# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+-#
+-# When uploading crates to the registry Cargo will automatically
+-# "normalize" Cargo.toml files for maximal compatibility
+-# with all versions of Cargo and also rewrite `path` dependencies
+-# to registry (e.g., crates.io) dependencies
+-#
+-# If you believe there's an error in this file please file an
+-# issue against the rust-lang/cargo repository. If you're
+-# editing this file be aware that the upstream Cargo.toml
+-# will likely look very different (and much more reasonable)
+-
+ [package]
+-edition = "2018"
+ name = "authenticator"
+ version = "0.3.1"
+ authors = ["J.C. Jones <jc@mozilla.com>", "Tim Taubert <ttaubert@mozilla.com>", "Kyle Machulis <kyle@nonpolynomial.com>"]
+-description = "Library for interacting with CTAP1/2 security keys for Web Authentication. Used by Firefox."
+ keywords = ["ctap2", "u2f", "fido", "webauthn"]
+ categories = ["cryptography", "hardware-support", "os"]
+-license = "MPL-2.0"
+ repository = "https://github.com/mozilla/authenticator-rs/"
+-[dependencies.base64]
+-version = "^0.10"
+-optional = true
+-
+-[dependencies.bitflags]
+-version = "1.0"
+-
+-[dependencies.bytes]
+-version = "0.5"
+-features = ["serde"]
+-optional = true
+-
+-[dependencies.libc]
+-version = "0.2"
+-
+-[dependencies.log]
+-version = "0.4"
+-
+-[dependencies.rand]
+-version = "0.7"
+-
+-[dependencies.runloop]
+-version = "0.1.0"
+-
+-[dependencies.serde]
+-version = "1.0"
+-features = ["derive"]
+-optional = true
+-
+-[dependencies.serde_json]
+-version = "1.0"
+-optional = true
+-
+-[dependencies.tokio]
+-version = "0.2"
+-features = ["macros"]
+-optional = true
++license = "MPL-2.0"
++description = "Library for interacting with CTAP1/2 security keys for Web Authentication. Used by Firefox."
++edition = "2018"
+ 
+-[dependencies.warp]
+-version = "0.2.4"
+-optional = true
+-[dev-dependencies.assert_matches]
+-version = "1.2"
++[badges]
++travis-ci = { repository = "mozilla/authenticator-rs", branch = "master" }
++maintenance = { status = "actively-developed" }
+ 
+-[dev-dependencies.base64]
+-version = "^0.10"
++[features]
++binding-recompile = ["bindgen"]
++webdriver = ["base64", "bytes", "warp", "tokio", "serde", "serde_json"]
+ 
+-[dev-dependencies.env_logger]
+-version = "^0.6"
++[target.'cfg(target_os = "linux")'.dependencies]
++libudev = "^0.2"
+ 
+-[dev-dependencies.getopts]
+-version = "^0.2"
++[target.'cfg(target_os = "freebsd")'.dependencies]
++devd-rs = "0.3"
+ 
+-[dev-dependencies.sha2]
+-version = "^0.8.2"
+-[build-dependencies.bindgen]
+-version = "^0.51"
+-optional = true
++[target.'cfg(target_os = "macos")'.dependencies]
++core-foundation = "0.9"
+ 
+-[features]
+-binding-recompile = ["bindgen"]
+-webdriver = ["base64", "bytes", "warp", "tokio", "serde", "serde_json"]
+-[target."cfg(target_os = \"freebsd\")".dependencies.devd-rs]
+-version = "0.3"
+-[target."cfg(target_os = \"linux\")".dependencies.libudev]
+-version = "^0.2"
+-[target."cfg(target_os = \"macos\")".dependencies.core-foundation]
+-version = "0.9"
+-[target."cfg(target_os = \"windows\")".dependencies.winapi]
++[target.'cfg(target_os = "windows")'.dependencies.winapi]
+ version = "^0.3"
+-features = ["handleapi", "hidclass", "hidpi", "hidusage", "setupapi"]
+-[badges.maintenance]
+-status = "actively-developed"
+-
+-[badges.travis-ci]
+-branch = "master"
+-repository = "mozilla/authenticator-rs"
++features = [
++    "handleapi",
++    "hidclass",
++    "hidpi",
++    "hidusage",
++    "setupapi",
++]
++
++[build-dependencies]
++bindgen = { version = "^0.58.1", optional = true }
++
++[dependencies]
++rand = "0.7"
++log = "0.4"
++libc = "0.2"
++runloop = "0.1.0"
++bitflags = "1.0"
++tokio = { version = "0.2", optional = true, features = ["macros"] }
++warp = { version = "0.2.4", optional = true }
++serde = { version = "1.0", optional = true, features = ["derive"] }
++serde_json = { version = "1.0", optional = true }
++bytes = { version = "0.5", optional = true, features = ["serde"] }
++base64 = { version = "^0.10", optional = true }
++
++[dev-dependencies]
++sha2 = "^0.8.2"
++base64 = "^0.10"
++env_logger = "^0.6"
++getopts = "^0.2"
++assert_matches = "1.2"
+diff --git a/third_party/rust/authenticator/build.rs b/third_party/rust/authenticator/build.rs
+index 299e4df6d7331..c972d85b898ea 100644
+--- a/third_party/rust/authenticator/build.rs
++++ b/third_party/rust/authenticator/build.rs
+@@ -45,6 +45,8 @@ fn main() {
+         "ioctl_aarch64be.rs"
+     } else if cfg!(all(target_arch = "s390x", target_endian = "big")) {
+         "ioctl_s390xbe.rs"
++    } else if cfg!(all(target_arch = "riscv64", target_endian = "little")) {
++        "ioctl_riscv64.rs"
+     } else {
+         panic!("architecture not supported");
+     };
+diff --git a/third_party/rust/authenticator/src/linux/hidwrapper.rs b/third_party/rust/authenticator/src/linux/hidwrapper.rs
+index ea1a39051b63a..82aabc6301017 100644
+--- a/third_party/rust/authenticator/src/linux/hidwrapper.rs
++++ b/third_party/rust/authenticator/src/linux/hidwrapper.rs
+@@ -46,3 +46,6 @@ include!("ioctl_aarch64be.rs");
+ 
+ #[cfg(all(target_arch = "s390x", target_endian = "big"))]
+ include!("ioctl_s390xbe.rs");
++
++#[cfg(all(target_arch = "riscv64", target_endian = "little"))]
++include!("ioctl_riscv64.rs");
+diff --git a/third_party/rust/authenticator/src/linux/ioctl_riscv64.rs b/third_party/rust/authenticator/src/linux/ioctl_riscv64.rs
+new file mode 100644
+index 0000000000000..a784e9bf4600b
+--- /dev/null
++++ b/third_party/rust/authenticator/src/linux/ioctl_riscv64.rs
+@@ -0,0 +1,5 @@
++/* automatically generated by rust-bindgen */
++
++pub type __u32 = ::std::os::raw::c_uint;
++pub const _HIDIOCGRDESCSIZE: __u32 = 2147764225;
++pub const _HIDIOCGRDESC: __u32 = 2416199682;
+--- a/toolkit/library/rust/shared/Cargo.toml    2022-02-10 20:41:52.387673027 +0800
++++ b/toolkit/library/rust/shared/Cargo.toml    2022-02-12 17:34:42.861720793 +0800
+@@ -24,7 +24,7 @@
+ cubeb-pulse = { git = "https://github.com/mozilla/cubeb-pulse-rs", rev="f2456201dbfdc467b80f0ff6bbb1b8a6faf7df02", optional = true, features=["pulse-dlopen"] }
+ cubeb-sys = { version = "0.9", optional = true, features=["gecko-in-tree"] }
+ encoding_glue = { path = "../../../../intl/encoding_glue" }
+-authenticator = "0.3.1"
++authenticator = { git = "https://github.com/makotokato/authenticator-rs", rev = "eed8919d50559f4959e2d7d2af7b4d48869b5366" }
+ gkrust_utils = { path = "../../../../xpcom/rust/gkrust_utils" }
+ gecko_logger = { path = "../../../../xpcom/rust/gecko_logger" }
+ rsdparsa_capi = { path = "../../../../dom/media/webrtc/sdp/rsdparsa_capi" }
+From a418c651c88cd2682c4cfe61e9f57b5389078c09 Mon Sep 17 00:00:00 2001
+From: Makoto Kato <m_kato@ga2.so-net.ne.jp>
+Date: Thu, 17 Jun 2021 21:50:49 +0900
+Subject: [PATCH] signal handler
+
+---
+ js/src/wasm/WasmSignalHandlers.cpp | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+--- a/js/src/wasm/WasmSignalHandlers.cpp        2022-02-12 19:29:33.566924464 +0800
++++ b/js/src/wasm/WasmSignalHandlers.cpp        2022-02-12 19:50:29.499985612 +0800
+@@ -156,6 +156,11 @@
+ #      define R01_sig(p) ((p)->uc_mcontext.gp_regs[1])
+ #      define R32_sig(p) ((p)->uc_mcontext.gp_regs[32])
+ #    endif
++#  if defined(__linux__) && defined(__riscv) && __riscv_xlen == 64
++#    define EPC_sig(p) ((p)->uc_mcontext.__gregs[0])
++#    define X02_sig(p) ((p)->uc_mcontext.__gregs[2])
++#    define X08_sig(p) ((p)->uc_mcontext.__gregs[8])
++#  endif
+ #  elif defined(__NetBSD__)
+ #    define EIP_sig(p) ((p)->uc_mcontext.__gregs[_REG_EIP])
+ #    define EBP_sig(p) ((p)->uc_mcontext.__gregs[_REG_EBP])
+@@ -376,6 +381,10 @@
+ #    define PC_sig(p) R32_sig(p)
+ #    define SP_sig(p) R01_sig(p)
+ #    define FP_sig(p) R01_sig(p)
++#elif defined(__riscv) && __riscv_xlen == 64
++#  define PC_sig(p) EPC_sig(p)
++#  define SP_sig(p) X02_sig(p)
++#  define FP_sig(p) X08_sig(p)
+ #  endif
+ 
+ static void SetContextPC(CONTEXT* context, uint8_t* pc) {
+From b6be52755af09f55e78d86bdd02a99efa0d16f9f Mon Sep 17 00:00:00 2001
+From: Makoto Kato <m_kato@ga2.so-net.ne.jp>
+Date: Fri, 28 Jan 2022 12:21:06 +0900
+Subject: [PATCH] mach vendor rust
+
+---
+ .cargo/config.in                              |   10 +-
+ Cargo.lock                                    |   29 +-
+ Cargo.toml                                    |    3 +-
+ .../mozbuild/mozbuild/vendor/vendor_rust.py   |    1 +
+ third_party/rust/alsa/.cargo-checksum.json    |    2 +-
+ third_party/rust/alsa/Cargo.toml              |    8 +-
+ third_party/rust/alsa/src/direct/pcm.rs       |    2 +-
+ third_party/rust/alsa/src/error.rs            |    1 -
+ third_party/rust/alsa/src/lib.rs              |    8 +-
+ third_party/rust/alsa/src/mixer.rs            |    8 +
+ third_party/rust/alsa/src/pcm.rs              |   78 +-
+ .../rust/bitflags/.cargo-checksum.json        |    2 +-
+ third_party/rust/bitflags/CHANGELOG.md        |   57 -
+ third_party/rust/bitflags/Cargo.toml          |   34 +-
+ third_party/rust/bitflags/README.md           |   12 +-
+ third_party/rust/bitflags/build.rs            |   44 +
+ third_party/rust/bitflags/src/lib.rs          |  873 ++----
+ third_party/rust/bitflags/tests/basic.rs      |   20 -
+ .../bitflags/tests/compile-fail/impls/copy.rs |   10 -
+ .../tests/compile-fail/impls/copy.stderr.beta |   27 -
+ .../bitflags/tests/compile-fail/impls/eq.rs   |   10 -
+ .../tests/compile-fail/impls/eq.stderr.beta   |   55 -
+ .../non_integer_base/all_defined.rs           |  123 -
+ .../non_integer_base/all_defined.stderr.beta  |   27 -
+ .../non_integer_base/all_missing.rs           |   13 -
+ .../non_integer_base/all_missing.stderr.beta  |   13 -
+ .../compile-fail/visibility/private_field.rs  |   13 -
+ .../visibility/private_field.stderr.beta      |   10 -
+ .../compile-fail/visibility/private_flags.rs  |   18 -
+ .../visibility/private_flags.stderr.beta      |   18 -
+ .../compile-fail/visibility/pub_const.rs      |    9 -
+ .../visibility/pub_const.stderr.beta          |    5 -
+ .../tests/compile-pass/impls/convert.rs       |   17 -
+ .../tests/compile-pass/impls/default.rs       |   10 -
+ .../compile-pass/impls/inherent_methods.rs    |   15 -
+ .../tests/compile-pass/redefinition/core.rs   |   14 -
+ .../compile-pass/redefinition/stringify.rs    |   19 -
+ .../bitflags/tests/compile-pass/repr/c.rs     |   10 -
+ .../tests/compile-pass/repr/transparent.rs    |   10 -
+ .../compile-pass/visibility/bits_field.rs     |   11 -
+ .../tests/compile-pass/visibility/pub_in.rs   |   19 -
+ third_party/rust/bitflags/tests/compile.rs    |   63 -
+ third_party/rust/midir/.cargo-checksum.json   |    2 +-
+ third_party/rust/midir/Cargo.toml             |    4 +-
+ .../rust/nix-0.15.0/.cargo-checksum.json      |    1 +
+ third_party/rust/nix-0.15.0/CHANGELOG.md      |  742 +++++
+ third_party/rust/nix-0.15.0/CONTRIBUTING.md   |  114 +
+ third_party/rust/nix-0.15.0/CONVENTIONS.md    |   87 +
+ third_party/rust/nix-0.15.0/Cargo.toml        |   71 +
+ third_party/rust/nix-0.15.0/LICENSE           |   21 +
+ third_party/rust/nix-0.15.0/README.md         |  111 +
+ third_party/rust/{nix => nix-0.15.0}/build.rs |    0
+ third_party/rust/nix-0.15.0/src/dir.rs        |  193 ++
+ third_party/rust/nix-0.15.0/src/errno.rs      | 1963 ++++++++++++++
+ .../{nix => nix-0.15.0}/src/errno_dragonfly.c |    0
+ third_party/rust/nix-0.15.0/src/fcntl.rs      |  506 ++++
+ third_party/rust/nix-0.15.0/src/features.rs   |  103 +
+ third_party/rust/nix-0.15.0/src/ifaddrs.rs    |  146 +
+ third_party/rust/nix-0.15.0/src/kmod.rs       |  123 +
+ third_party/rust/nix-0.15.0/src/lib.rs        |  284 ++
+ third_party/rust/nix-0.15.0/src/macros.rs     |  264 ++
+ third_party/rust/nix-0.15.0/src/mount.rs      |   98 +
+ third_party/rust/nix-0.15.0/src/mqueue.rs     |  162 ++
+ third_party/rust/nix-0.15.0/src/net/if_.rs    |  268 ++
+ third_party/rust/nix-0.15.0/src/net/mod.rs    |    4 +
+ third_party/rust/nix-0.15.0/src/poll.rs       |  143 +
+ third_party/rust/nix-0.15.0/src/pty.rs        |  326 +++
+ third_party/rust/nix-0.15.0/src/sched.rs      |  147 +
+ third_party/rust/nix-0.15.0/src/sys/aio.rs    | 1280 +++++++++
+ third_party/rust/nix-0.15.0/src/sys/epoll.rs  |  109 +
+ third_party/rust/nix-0.15.0/src/sys/event.rs  |  351 +++
+ .../rust/nix-0.15.0/src/sys/eventfd.rs        |   18 +
+ .../rust/nix-0.15.0/src/sys/inotify.rs        |  230 ++
+ .../rust/nix-0.15.0/src/sys/ioctl/bsd.rs      |  102 +
+ .../rust/nix-0.15.0/src/sys/ioctl/linux.rs    |  140 +
+ .../rust/nix-0.15.0/src/sys/ioctl/mod.rs      |  778 ++++++
+ third_party/rust/nix-0.15.0/src/sys/memfd.rs  |   20 +
+ third_party/rust/nix-0.15.0/src/sys/mman.rs   |  325 +++
+ third_party/rust/nix-0.15.0/src/sys/mod.rs    |  100 +
+ .../rust/nix-0.15.0/src/sys/pthread.rs        |   13 +
+ .../rust/nix-0.15.0/src/sys/ptrace/bsd.rs     |  170 ++
+ .../rust/nix-0.15.0/src/sys/ptrace/linux.rs   |  402 +++
+ .../rust/nix-0.15.0/src/sys/ptrace/mod.rs     |   22 +
+ third_party/rust/nix-0.15.0/src/sys/quota.rs  |  273 ++
+ third_party/rust/nix-0.15.0/src/sys/reboot.rs |   45 +
+ third_party/rust/nix-0.15.0/src/sys/select.rs |  334 +++
+ .../rust/nix-0.15.0/src/sys/sendfile.rs       |  200 ++
+ third_party/rust/nix-0.15.0/src/sys/signal.rs |  966 +++++++
+ .../rust/nix-0.15.0/src/sys/signalfd.rs       |  170 ++
+ .../rust/nix-0.15.0/src/sys/socket/addr.rs    | 1278 +++++++++
+ .../rust/nix-0.15.0/src/sys/socket/mod.rs     | 1294 +++++++++
+ .../rust/nix-0.15.0/src/sys/socket/sockopt.rs |  680 +++++
+ third_party/rust/nix-0.15.0/src/sys/stat.rs   |  294 ++
+ third_party/rust/nix-0.15.0/src/sys/statfs.rs |  548 ++++
+ .../rust/nix-0.15.0/src/sys/statvfs.rs        |  160 ++
+ .../rust/nix-0.15.0/src/sys/sysinfo.rs        |   72 +
+ .../rust/nix-0.15.0/src/sys/termios.rs        | 1107 ++++++++
+ third_party/rust/nix-0.15.0/src/sys/time.rs   |  542 ++++
+ third_party/rust/nix-0.15.0/src/sys/uio.rs    |  194 ++
+ .../rust/nix-0.15.0/src/sys/utsname.rs        |   67 +
+ third_party/rust/nix-0.15.0/src/sys/wait.rs   |  239 ++
+ third_party/rust/nix-0.15.0/src/ucontext.rs   |   39 +
+ third_party/rust/nix-0.15.0/src/unistd.rs     | 2394 +++++++++++++++++
+ third_party/rust/nix-0.15.0/test/sys/mod.rs   |   38 +
+ .../rust/nix-0.15.0/test/sys/test_aio.rs      |  654 +++++
+ .../rust/nix-0.15.0/test/sys/test_aio_drop.rs |   32 +
+ .../rust/nix-0.15.0/test/sys/test_epoll.rs    |   24 +
+ .../rust/nix-0.15.0/test/sys/test_inotify.rs  |   65 +
+ .../rust/nix-0.15.0/test/sys/test_ioctl.rs    |  334 +++
+ .../test/sys/test_lio_listio_resubmit.rs      |  111 +
+ .../rust/nix-0.15.0/test/sys/test_pthread.rs  |   15 +
+ .../rust/nix-0.15.0/test/sys/test_ptrace.rs   |  107 +
+ .../rust/nix-0.15.0/test/sys/test_select.rs   |   54 +
+ .../rust/nix-0.15.0/test/sys/test_signal.rs   |  104 +
+ .../rust/nix-0.15.0/test/sys/test_signalfd.rs |   25 +
+ .../rust/nix-0.15.0/test/sys/test_socket.rs   | 1066 ++++++++
+ .../rust/nix-0.15.0/test/sys/test_sockopt.rs  |   53 +
+ .../rust/nix-0.15.0/test/sys/test_sysinfo.rs  |   18 +
+ .../rust/nix-0.15.0/test/sys/test_termios.rs  |  136 +
+ .../rust/nix-0.15.0/test/sys/test_uio.rs      |  241 ++
+ .../rust/nix-0.15.0/test/sys/test_wait.rs     |  104 +
+ third_party/rust/nix-0.15.0/test/test.rs      |  149 +
+ third_party/rust/nix-0.15.0/test/test_dir.rs  |   46 +
+ .../rust/nix-0.15.0/test/test_fcntl.rs        |  234 ++
+ .../test/test_kmod/hello_mod/Makefile         |    7 +
+ .../test/test_kmod/hello_mod/hello.c          |   26 +
+ .../rust/nix-0.15.0/test/test_kmod/mod.rs     |  166 ++
+ .../rust/nix-0.15.0/test/test_mount.rs        |  238 ++
+ third_party/rust/nix-0.15.0/test/test_mq.rs   |  152 ++
+ third_party/rust/nix-0.15.0/test/test_net.rs  |   12 +
+ .../rust/nix-0.15.0/test/test_nix_path.rs     |    0
+ third_party/rust/nix-0.15.0/test/test_poll.rs |   50 +
+ third_party/rust/nix-0.15.0/test/test_pty.rs  |  235 ++
+ .../nix-0.15.0/test/test_ptymaster_drop.rs    |   21 +
+ .../rust/nix-0.15.0/test/test_sendfile.rs     |  129 +
+ third_party/rust/nix-0.15.0/test/test_stat.rs |  296 ++
+ .../rust/nix-0.15.0/test/test_unistd.rs       |  669 +++++
+ third_party/rust/nix/.cargo-checksum.json     |    2 +-
+ third_party/rust/nix/CHANGELOG.md             |  306 ++-
+ third_party/rust/nix/CONTRIBUTING.md          |   10 +-
+ third_party/rust/nix/CONVENTIONS.md           |    9 +-
+ third_party/rust/nix/Cargo.toml               |   40 +-
+ third_party/rust/nix/README.md                |   22 +-
+ third_party/rust/nix/src/dir.rs               |   99 +-
+ third_party/rust/nix/src/env.rs               |   53 +
+ third_party/rust/nix/src/errno.rs             |  480 +++-
+ third_party/rust/nix/src/fcntl.rs             |  268 +-
+ third_party/rust/nix/src/features.rs          |    7 +-
+ third_party/rust/nix/src/ifaddrs.rs           |   29 +-
+ third_party/rust/nix/src/kmod.rs              |    4 +-
+ third_party/rust/nix/src/lib.rs               |   74 +-
+ third_party/rust/nix/src/macros.rs            |   79 +-
+ third_party/rust/nix/src/mount.rs             |   43 +-
+ third_party/rust/nix/src/mqueue.rs            |   65 +-
+ third_party/rust/nix/src/net/if_.rs           |    3 +-
+ third_party/rust/nix/src/poll.rs              |   29 +-
+ third_party/rust/nix/src/pty.rs               |   80 +-
+ third_party/rust/nix/src/sched.rs             |  104 +-
+ third_party/rust/nix/src/sys/aio.rs           |   44 +-
+ third_party/rust/nix/src/sys/epoll.rs         |    8 +-
+ third_party/rust/nix/src/sys/event.rs         |   45 +-
+ third_party/rust/nix/src/sys/eventfd.rs       |    4 +-
+ third_party/rust/nix/src/sys/inotify.rs       |   37 +-
+ third_party/rust/nix/src/sys/ioctl/bsd.rs     |    4 +-
+ third_party/rust/nix/src/sys/ioctl/linux.rs   |    3 +-
+ third_party/rust/nix/src/sys/ioctl/mod.rs     |   12 +-
+ third_party/rust/nix/src/sys/memfd.rs         |    4 +-
+ third_party/rust/nix/src/sys/mman.rs          |  136 +-
+ third_party/rust/nix/src/sys/mod.rs           |   10 +
+ third_party/rust/nix/src/sys/personality.rs   |   70 +
+ third_party/rust/nix/src/sys/ptrace/bsd.rs    |   25 +-
+ third_party/rust/nix/src/sys/ptrace/linux.rs  |  164 +-
+ third_party/rust/nix/src/sys/quota.rs         |   16 +-
+ third_party/rust/nix/src/sys/reboot.rs        |    8 +-
+ third_party/rust/nix/src/sys/select.rs        |  140 +-
+ third_party/rust/nix/src/sys/sendfile.rs      |   11 +-
+ third_party/rust/nix/src/sys/signal.rs        |  300 ++-
+ third_party/rust/nix/src/sys/signalfd.rs      |   28 +-
+ third_party/rust/nix/src/sys/socket/addr.rs   |  205 +-
+ third_party/rust/nix/src/sys/socket/mod.rs    |  930 +++++--
+ .../rust/nix/src/sys/socket/sockopt.rs        |  117 +-
+ third_party/rust/nix/src/sys/stat.rs          |   39 +-
+ third_party/rust/nix/src/sys/statfs.rs        |  216 +-
+ third_party/rust/nix/src/sys/statvfs.rs       |   21 +-
+ third_party/rust/nix/src/sys/sysinfo.rs       |   19 +-
+ third_party/rust/nix/src/sys/termios.rs       |  217 +-
+ third_party/rust/nix/src/sys/time.rs          |   79 +-
+ third_party/rust/nix/src/sys/timerfd.rs       |  285 ++
+ third_party/rust/nix/src/sys/uio.rs           |   18 +-
+ third_party/rust/nix/src/sys/utsname.rs       |    8 +-
+ third_party/rust/nix/src/sys/wait.rs          |   43 +-
+ third_party/rust/nix/src/time.rs              |  260 ++
+ third_party/rust/nix/src/ucontext.rs          |   25 +-
+ third_party/rust/nix/src/unistd.rs            |  809 ++++--
+ third_party/rust/nix/test/common/mod.rs       |  127 +
+ third_party/rust/nix/test/sys/mod.rs          |    7 +
+ third_party/rust/nix/test/sys/test_aio.rs     |  104 +-
+ .../rust/nix/test/sys/test_aio_drop.rs        |    4 +-
+ third_party/rust/nix/test/sys/test_ioctl.rs   |   55 +-
+ .../nix/test/sys/test_lio_listio_resubmit.rs  |    4 -
+ third_party/rust/nix/test/sys/test_mman.rs    |   80 +
+ third_party/rust/nix/test/sys/test_pthread.rs |    4 +-
+ third_party/rust/nix/test/sys/test_ptrace.rs  |   79 +-
+ third_party/rust/nix/test/sys/test_select.rs  |    2 +-
+ third_party/rust/nix/test/sys/test_signal.rs  |   25 +-
+ .../rust/nix/test/sys/test_signalfd.rs        |    6 +-
+ third_party/rust/nix/test/sys/test_socket.rs  |  555 +++-
+ third_party/rust/nix/test/sys/test_sockopt.rs |   43 +
+ third_party/rust/nix/test/sys/test_termios.rs |   22 +-
+ third_party/rust/nix/test/sys/test_timerfd.rs |   61 +
+ third_party/rust/nix/test/sys/test_uio.rs     |   12 +-
+ third_party/rust/nix/test/sys/test_wait.rs    |   21 +-
+ third_party/rust/nix/test/test.rs             |   71 +-
+ third_party/rust/nix/test/test_clearenv.rs    |    9 +
+ third_party/rust/nix/test/test_dir.rs         |    7 +-
+ third_party/rust/nix/test/test_fcntl.rs       |  199 +-
+ third_party/rust/nix/test/test_kmod/mod.rs    |   31 +-
+ third_party/rust/nix/test/test_mount.rs       |    7 +-
+ third_party/rust/nix/test/test_mq.rs          |   28 +-
+ third_party/rust/nix/test/test_poll.rs        |   27 +-
+ third_party/rust/nix/test/test_pty.rs         |  104 +-
+ .../rust/nix/test/test_ptymaster_drop.rs      |   41 +-
+ third_party/rust/nix/test/test_sched.rs       |   32 +
+ third_party/rust/nix/test/test_stat.rs        |   61 +-
+ third_party/rust/nix/test/test_time.rs        |   56 +
+ third_party/rust/nix/test/test_unistd.rs      |  575 +++-
+ 226 files changed, 33484 insertions(+), 3322 deletions(-)
+ create mode 100644 third_party/rust/bitflags/build.rs
+ delete mode 100644 third_party/rust/bitflags/tests/basic.rs
+ delete mode 100644 third_party/rust/bitflags/tests/compile-fail/impls/copy.rs
+ delete mode 100644 third_party/rust/bitflags/tests/compile-fail/impls/copy.stderr.beta
+ delete mode 100644 third_party/rust/bitflags/tests/compile-fail/impls/eq.rs
+ delete mode 100644 third_party/rust/bitflags/tests/compile-fail/impls/eq.stderr.beta
+ delete mode 100644 third_party/rust/bitflags/tests/compile-fail/non_integer_base/all_defined.rs
+ delete mode 100644 third_party/rust/bitflags/tests/compile-fail/non_integer_base/all_defined.stderr.beta
+ delete mode 100644 third_party/rust/bitflags/tests/compile-fail/non_integer_base/all_missing.rs
+ delete mode 100644 third_party/rust/bitflags/tests/compile-fail/non_integer_base/all_missing.stderr.beta
+ delete mode 100644 third_party/rust/bitflags/tests/compile-fail/visibility/private_field.rs
+ delete mode 100644 third_party/rust/bitflags/tests/compile-fail/visibility/private_field.stderr.beta
+ delete mode 100644 third_party/rust/bitflags/tests/compile-fail/visibility/private_flags.rs
+ delete mode 100644 third_party/rust/bitflags/tests/compile-fail/visibility/private_flags.stderr.beta
+ delete mode 100644 third_party/rust/bitflags/tests/compile-fail/visibility/pub_const.rs
+ delete mode 100644 third_party/rust/bitflags/tests/compile-fail/visibility/pub_const.stderr.beta
+ delete mode 100644 third_party/rust/bitflags/tests/compile-pass/impls/convert.rs
+ delete mode 100644 third_party/rust/bitflags/tests/compile-pass/impls/default.rs
+ delete mode 100644 third_party/rust/bitflags/tests/compile-pass/impls/inherent_methods.rs
+ delete mode 100644 third_party/rust/bitflags/tests/compile-pass/redefinition/core.rs
+ delete mode 100644 third_party/rust/bitflags/tests/compile-pass/redefinition/stringify.rs
+ delete mode 100644 third_party/rust/bitflags/tests/compile-pass/repr/c.rs
+ delete mode 100644 third_party/rust/bitflags/tests/compile-pass/repr/transparent.rs
+ delete mode 100644 third_party/rust/bitflags/tests/compile-pass/visibility/bits_field.rs
+ delete mode 100644 third_party/rust/bitflags/tests/compile-pass/visibility/pub_in.rs
+ delete mode 100644 third_party/rust/bitflags/tests/compile.rs
+ create mode 100644 third_party/rust/nix-0.15.0/.cargo-checksum.json
+ create mode 100644 third_party/rust/nix-0.15.0/CHANGELOG.md
+ create mode 100644 third_party/rust/nix-0.15.0/CONTRIBUTING.md
+ create mode 100644 third_party/rust/nix-0.15.0/CONVENTIONS.md
+ create mode 100644 third_party/rust/nix-0.15.0/Cargo.toml
+ create mode 100644 third_party/rust/nix-0.15.0/LICENSE
+ create mode 100644 third_party/rust/nix-0.15.0/README.md
+ rename third_party/rust/{nix => nix-0.15.0}/build.rs (100%)
+ create mode 100644 third_party/rust/nix-0.15.0/src/dir.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/errno.rs
+ rename third_party/rust/{nix => nix-0.15.0}/src/errno_dragonfly.c (100%)
+ create mode 100644 third_party/rust/nix-0.15.0/src/fcntl.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/features.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/ifaddrs.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/kmod.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/lib.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/macros.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/mount.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/mqueue.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/net/if_.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/net/mod.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/poll.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/pty.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sched.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/aio.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/epoll.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/event.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/eventfd.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/inotify.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/ioctl/bsd.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/ioctl/linux.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/ioctl/mod.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/memfd.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/mman.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/mod.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/pthread.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/ptrace/bsd.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/ptrace/linux.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/ptrace/mod.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/quota.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/reboot.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/select.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/sendfile.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/signal.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/signalfd.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/socket/addr.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/socket/mod.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/socket/sockopt.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/stat.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/statfs.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/statvfs.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/sysinfo.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/termios.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/time.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/uio.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/utsname.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/sys/wait.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/ucontext.rs
+ create mode 100644 third_party/rust/nix-0.15.0/src/unistd.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/sys/mod.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/sys/test_aio.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/sys/test_aio_drop.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/sys/test_epoll.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/sys/test_inotify.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/sys/test_ioctl.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/sys/test_lio_listio_resubmit.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/sys/test_pthread.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/sys/test_ptrace.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/sys/test_select.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/sys/test_signal.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/sys/test_signalfd.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/sys/test_socket.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/sys/test_sockopt.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/sys/test_sysinfo.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/sys/test_termios.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/sys/test_uio.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/sys/test_wait.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/test.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/test_dir.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/test_fcntl.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/test_kmod/hello_mod/Makefile
+ create mode 100644 third_party/rust/nix-0.15.0/test/test_kmod/hello_mod/hello.c
+ create mode 100644 third_party/rust/nix-0.15.0/test/test_kmod/mod.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/test_mount.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/test_mq.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/test_net.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/test_nix_path.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/test_poll.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/test_pty.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/test_ptymaster_drop.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/test_sendfile.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/test_stat.rs
+ create mode 100644 third_party/rust/nix-0.15.0/test/test_unistd.rs
+ create mode 100644 third_party/rust/nix/src/env.rs
+ create mode 100644 third_party/rust/nix/src/sys/personality.rs
+ create mode 100644 third_party/rust/nix/src/sys/timerfd.rs
+ create mode 100644 third_party/rust/nix/src/time.rs
+ create mode 100644 third_party/rust/nix/test/common/mod.rs
+ create mode 100644 third_party/rust/nix/test/sys/test_mman.rs
+ create mode 100644 third_party/rust/nix/test/sys/test_timerfd.rs
+ create mode 100644 third_party/rust/nix/test/test_clearenv.rs
+ create mode 100644 third_party/rust/nix/test/test_sched.rs
+ create mode 100644 third_party/rust/nix/test/test_time.rs
+
+diff --git a/Cargo.lock b/Cargo.lock
+index edc5ef5ff2d98..f6240163e1440 100644
+--- a/Cargo.lock
++++ b/Cargo.lock
+@@ -25,14 +25,14 @@ dependencies = [
+ 
+ [[package]]
+ name = "alsa"
+-version = "0.4.3"
++version = "0.5.0"
+ source = "registry+https://github.com/rust-lang/crates.io-index"
+-checksum = "eb213f6b3e4b1480a60931ca2035794aa67b73103d254715b1db7b70dcb3c934"
++checksum = "75c4da790adcb2ce5e758c064b4f3ec17a30349f9961d3e5e6c9688b052a9e18"
+ dependencies = [
+  "alsa-sys",
+  "bitflags",
+  "libc",
+- "nix",
++ "nix 0.20.2",
+ ]
+ 
+ [[package]]
+@@ -427,9 +427,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
+ 
+ [[package]]
+ name = "bitflags"
+-version = "1.3.2"
++version = "1.2.1"
+ source = "registry+https://github.com/rust-lang/crates.io-index"
+-checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
++checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+ 
+ [[package]]
+ name = "bitflags_serde_shim"
+@@ -3073,7 +3073,7 @@ dependencies = [
+ [[package]]
+ name = "midir"
+ version = "0.7.0"
+-source = "git+https://github.com/mozilla/midir.git?rev=4c11f0ffb5d6a10de4aff40a7b81218b33b94e6f#4c11f0ffb5d6a10de4aff40a7b81218b33b94e6f"
++source = "git+https://github.com/makotokato/midir.git?rev=6140b2825dd4dc2b40e49e154ca7596e7b9a131a#6140b2825dd4dc2b40e49e154ca7596e7b9a131a"
+ dependencies = [
+  "alsa",
+  "bitflags",
+@@ -3081,7 +3081,7 @@ dependencies = [
+  "js-sys",
+  "libc",
+  "memalloc",
+- "nix",
++ "nix 0.20.2",
+  "wasm-bindgen",
+  "web-sys",
+  "winapi",
+@@ -3123,7 +3123,7 @@ dependencies = [
+  "libc",
+  "memmap2 0.2.3",
+  "memoffset 0.5.6",
+- "nix",
++ "nix 0.15.0",
+  "tempfile",
+  "thiserror",
+ ]
+@@ -3535,6 +3535,19 @@ dependencies = [
+  "void",
+ ]
+ 
++[[package]]
++name = "nix"
++version = "0.20.2"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "f5e06129fb611568ef4e868c14b326274959aa70ff7776e9d55323531c374945"
++dependencies = [
++ "bitflags",
++ "cc",
++ "cfg-if 1.0.0",
++ "libc",
++ "memoffset 0.6.5",
++]
++
+ [[package]]
+ name = "nom"
+ version = "5.1.2"
+diff --git a/Cargo.toml b/Cargo.toml
+index 1c2437f1f5675..2923c7e5ea9bf 100644
+--- a/Cargo.toml        2022-03-10 14:19:47.963772765 +0800
++++ b/Cargo.toml        2022-03-10 14:33:46.354649188 +0800
+@@ -103,13 +103,14 @@
+ moz_asserts = { path = "mozglue/static/rust/moz_asserts" }
+ 
+ # Other overrides
++authenticator = { git = "https://github.com/makotokato/authenticator-rs", rev="eed8919d50559f4959e2d7d2af7b4d48869b5366" }
+ async-task = { git = "https://github.com/smol-rs/async-task", rev="f6488e35beccb26eb6e85847b02aa78a42cd3d0e" }
+ chardetng = { git = "https://github.com/hsivonen/chardetng", rev="3484d3e3ebdc8931493aa5df4d7ee9360a90e76b" }
+ chardetng_c = { git = "https://github.com/hsivonen/chardetng_c", rev="ed8a4c6f900a90d4dbc1d64b856e61490a1c3570" }
+ coremidi = { git = "https://github.com/chris-zen/coremidi.git", rev="fc68464b5445caf111e41f643a2e69ccce0b4f83" }
+ libudev-sys = { path = "dom/webauthn/libudev-sys" }
+ packed_simd = { git = "https://github.com/hsivonen/packed_simd", rev="8b4bd7d8229660a749dbe419a57ea01df9de5453" }
+-midir = { git = "https://github.com/mozilla/midir.git", rev = "4c11f0ffb5d6a10de4aff40a7b81218b33b94e6f" }
++midir = { git = "https://github.com/makotokato/midir.git", rev = "6140b2825dd4dc2b40e49e154ca7596e7b9a131a" }
+ minidump_writer_linux = { git = "https://github.com/msirringhaus/minidump_writer_linux.git", rev = "029ac0d54b237f27dc7d8d4e51bc0fb076e5e852" }
+ 
+ # Patch mio 0.6 to use winapi 0.3 and miow 0.3, getting rid of winapi 0.2.
+
+diff --git a/third_party/rust/alsa/.cargo-checksum.json b/third_party/rust/alsa/.cargo-checksum.json
+index 17227c0a74d16..2bd6b2e2ce47b 100644
+--- a/third_party/rust/alsa/.cargo-checksum.json
++++ b/third_party/rust/alsa/.cargo-checksum.json
+@@ -1 +1 @@
+-{"files":{"Cargo.toml":"5c7a276dd872b47ff86f892e5d8991f38fbe3d61b64eb7138a4ee7ed43d437b7","README.md":"4ccf86e184eda628989919a15560c1ada2c00808cf34740f6e8de466338a1d48","src/card.rs":"f49c6cd6afb83848d34ce7a2e71ede2741ef60262d073be631347871c2768401","src/chmap.rs":"c639f9018fe7d49179a64b73d4f7ef418483c7b150b7edba61d81963c4056770","src/ctl_int.rs":"ebff40ad723a62632ed59840c15c4ec8e4cea2053e4f61d49bdae95e7a74da70","src/device_name.rs":"1e8ad5efbca9c4f062289213e3de8c3429d97a4acf6312c2016553b06e7fa57b","src/direct.rs":"fbd40addd2458bb0b3e856e5b0225fd24dc0ad46ce3662aef12635cf34ef7f55","src/direct/asound_ioctl.rs":"27c8935a0e7bd6e1925d947411c37ca81befba60468a6f2206da9fb08805be89","src/direct/ffi.rs":"aeb0871bd764198558557b5af1a1f6038efe8c8a400d77b4ddfc91143029ac90","src/direct/pcm.rs":"a258e7ba908ef6a2d7d0851ce5279ccc9f7b1579511f48550927fbe4306edaae","src/error.rs":"c8e9839123d760d49b58f46574445550c2c48b90c738b4daaf48aab8dd9a205f","src/hctl.rs":"cc33947cb0810d3edeec7b71686f0231d06c88b421
 4994605de7f4fd0f6de1a1","src/io.rs":"a6e21b94a265b7de56388e035b104877c8b6a0f5d10002c5931dacc90dd577fd","src/lib.rs":"df35e75bb2d83ddddcc90f4ed76e4bcef6843b3b2be09d9b8197c9ede564fbdf","src/mixer.rs":"d6610712f80eb4fd292d5b6e1d10723dfb245be4d85d0370a675034d83010e75","src/pcm.rs":"4259a5b33421e0b144de59da938af1ff1f70a1a3f6e0d2ab665dda4b94441d8c","src/poll.rs":"a6472dbcc96bcbdcc574563f305550df66870e48820d5e90609b0f105d12bb07","src/rawmidi.rs":"ca891bf1cd43ad59b1657efd58356f78ea476d5de999ed756eba74b729f0c184","src/seq.rs":"d229b36f12bf0161c87e0820fd4a3313f19718790e38e0b6294b7e6b1123c611"},"package":"eb213f6b3e4b1480a60931ca2035794aa67b73103d254715b1db7b70dcb3c934"}
+\ No newline at end of file
++{"files":{"Cargo.toml":"e057013b541a2bcf1d2b7aa79a2860fec402dad4ae434a66ad2cf1f4e40d31b9","README.md":"4ccf86e184eda628989919a15560c1ada2c00808cf34740f6e8de466338a1d48","src/card.rs":"f49c6cd6afb83848d34ce7a2e71ede2741ef60262d073be631347871c2768401","src/chmap.rs":"c639f9018fe7d49179a64b73d4f7ef418483c7b150b7edba61d81963c4056770","src/ctl_int.rs":"ebff40ad723a62632ed59840c15c4ec8e4cea2053e4f61d49bdae95e7a74da70","src/device_name.rs":"1e8ad5efbca9c4f062289213e3de8c3429d97a4acf6312c2016553b06e7fa57b","src/direct.rs":"fbd40addd2458bb0b3e856e5b0225fd24dc0ad46ce3662aef12635cf34ef7f55","src/direct/asound_ioctl.rs":"27c8935a0e7bd6e1925d947411c37ca81befba60468a6f2206da9fb08805be89","src/direct/ffi.rs":"aeb0871bd764198558557b5af1a1f6038efe8c8a400d77b4ddfc91143029ac90","src/direct/pcm.rs":"e8d464f08405e4edfc35be12d715012b3c765093794dd8fafc8991a5f4367c67","src/error.rs":"b37d9958dd200362c44d7015d1b03813efec183c9c76168f2608d1e798035ea1","src/hctl.rs":"cc33947cb0810d3edeec7b71686f0231d06c88b421
 4994605de7f4fd0f6de1a1","src/io.rs":"a6e21b94a265b7de56388e035b104877c8b6a0f5d10002c5931dacc90dd577fd","src/lib.rs":"b1235da87167b3a329b5a1a1d8670db0ab411676c0cdb2bfd1b8884bca34f469","src/mixer.rs":"a358bb2ad1db787348c29cdfeda339c4cd16c5a85f5cea8d7e0e9dda8335cbbd","src/pcm.rs":"6c5c87c9d959626d717c6e0e6f13248a56297a0cb390ab0e58d27ca7ad901cac","src/poll.rs":"a6472dbcc96bcbdcc574563f305550df66870e48820d5e90609b0f105d12bb07","src/rawmidi.rs":"ca891bf1cd43ad59b1657efd58356f78ea476d5de999ed756eba74b729f0c184","src/seq.rs":"d229b36f12bf0161c87e0820fd4a3313f19718790e38e0b6294b7e6b1123c611"},"package":"75c4da790adcb2ce5e758c064b4f3ec17a30349f9961d3e5e6c9688b052a9e18"}
+\ No newline at end of file
+diff --git a/third_party/rust/alsa/Cargo.toml b/third_party/rust/alsa/Cargo.toml
+index c7578fb0785b9..b4af1a6dae284 100644
+--- a/third_party/rust/alsa/Cargo.toml
++++ b/third_party/rust/alsa/Cargo.toml
+@@ -13,7 +13,7 @@
+ [package]
+ edition = "2018"
+ name = "alsa"
+-version = "0.4.3"
++version = "0.5.0"
+ authors = ["David Henningsson <diwic@ubuntu.com>"]
+ description = "Thin but safe wrappers for ALSA (Linux sound API)"
+ documentation = "http://docs.rs/alsa"
+@@ -23,16 +23,16 @@ categories = ["multimedia::audio", "api-bindings"]
+ license = "Apache-2.0/MIT"
+ repository = "https://github.com/diwic/alsa-rs"
+ [dependencies.alsa-sys]
+-version = "0.3.0"
++version = "0.3.1"
+ 
+ [dependencies.bitflags]
+ version = "1.2.1"
+ 
+ [dependencies.libc]
+-version = "0.2.65"
++version = "0.2.88"
+ 
+ [dependencies.nix]
+-version = "0.15"
++version = "0.20"
+ [badges.is-it-maintained-issue-resolution]
+ repository = "diwic/alsa-rs"
+ 
+diff --git a/third_party/rust/alsa/src/direct/pcm.rs b/third_party/rust/alsa/src/direct/pcm.rs
+index 13a16a993b030..f248a70c67031 100644
+--- a/third_party/rust/alsa/src/direct/pcm.rs
++++ b/third_party/rust/alsa/src/direct/pcm.rs
+@@ -19,7 +19,7 @@ don't expect it to work with, e g, the PulseAudio plugin or so.
+ For an example of how to use this mode, look in the "synth-example" directory.
+ */
+ 
+-use {libc, nix};
++use libc;
+ use std::{mem, ptr, fmt, cmp};
+ use crate::error::{Error, Result};
+ use std::os::unix::io::RawFd;
+diff --git a/third_party/rust/alsa/src/error.rs b/third_party/rust/alsa/src/error.rs
+index 4711b0fd2016d..25089c4cbd1d7 100644
+--- a/third_party/rust/alsa/src/error.rs
++++ b/third_party/rust/alsa/src/error.rs
+@@ -3,7 +3,6 @@
+ use libc::{c_void, c_int, c_char, free};
+ use std::{fmt, ptr, str};
+ use std::ffi::CStr;
+-use nix;
+ use std::error::Error as StdError;
+ 
+ /// ALSA error
+diff --git a/third_party/rust/alsa/src/lib.rs b/third_party/rust/alsa/src/lib.rs
+index cf172cb6c60c6..b1a98df7804f3 100644
+--- a/third_party/rust/alsa/src/lib.rs
++++ b/third_party/rust/alsa/src/lib.rs
+@@ -18,7 +18,7 @@ extern crate libc;
+ #[macro_use]
+ extern crate bitflags;
+ #[macro_use]
+-extern crate nix;
++extern crate nix as nix_the_crate;
+ 
+ macro_rules! alsa_enum {
+  ($(#[$attr:meta])+ $name:ident, $static_name:ident [$count:expr], $( $a:ident = $b:ident),* ,) =>
+@@ -125,3 +125,9 @@ pub use crate::io::Output;
+ mod chmap;
+ 
+ pub mod direct;
++
++/// Re-exports from the nix crate.
++pub mod nix {
++    pub use nix_the_crate::Error;
++    pub use nix_the_crate::errno;
++}
+diff --git a/third_party/rust/alsa/src/mixer.rs b/third_party/rust/alsa/src/mixer.rs
+index cb16247a85b62..834aafaf35c18 100644
+--- a/third_party/rust/alsa/src/mixer.rs
++++ b/third_party/rust/alsa/src/mixer.rs
+@@ -112,11 +112,19 @@ impl ops::Add for MilliBel {
+     fn add(self, rhs: Self) -> Self { MilliBel(self.0 + rhs.0) }
+ }
+ 
++impl ops::AddAssign for MilliBel {
++    fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0 }
++}
++
+ impl ops::Sub for MilliBel {
+     type Output = MilliBel;
+     fn sub(self, rhs: Self) -> Self { MilliBel(self.0 - rhs.0) }
+ }
+ 
++impl ops::SubAssign for MilliBel {
++    fn sub_assign(&mut self, rhs: Self) { self.0 -= rhs.0 }
++}
++
+ /// Wraps [snd_mixer_elem_t](http://www.alsa-project.org/alsa-doc/alsa-lib/group___mixer.html)
+ #[derive(Copy, Clone, Debug)]
+ pub struct Elem<'a>{
+diff --git a/third_party/rust/alsa/src/pcm.rs b/third_party/rust/alsa/src/pcm.rs
+index 359b44c6db2cb..5696df9dc691e 100644
+--- a/third_party/rust/alsa/src/pcm.rs
++++ b/third_party/rust/alsa/src/pcm.rs
+@@ -174,8 +174,7 @@ impl PCM {
+     }
+ 
+     pub fn status(&self) -> Result<Status> {
+-        let z = Status::new();
+-        acheck!(snd_pcm_status(self.0, z.ptr())).map(|_| z)
++        StatusBuilder::new().build(self)
+     }
+ 
+     fn verify_format(&self, f: Format) -> Result<()> {
+@@ -416,6 +415,7 @@ alsa_enum!(
+ );
+ 
+ alsa_enum!(
++    #[non_exhaustive]
+     /// [SND_PCM_FORMAT_xxx](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html) constants
+     Format, ALL_FORMATS[48],
+ 
+@@ -470,21 +470,21 @@ alsa_enum!(
+ );
+ 
+ impl Format {
+-    pub fn s16() -> Format { <i16 as IoFormat>::FORMAT }
+-    pub fn u16() -> Format { <u16 as IoFormat>::FORMAT }
+-    pub fn s32() -> Format { <i32 as IoFormat>::FORMAT }
+-    pub fn u32() -> Format { <u32 as IoFormat>::FORMAT }
+-    pub fn float() -> Format { <f32 as IoFormat>::FORMAT }
+-    pub fn float64() -> Format { <f64 as IoFormat>::FORMAT }
++    pub const fn s16() -> Format { <i16 as IoFormat>::FORMAT }
++    pub const fn u16() -> Format { <u16 as IoFormat>::FORMAT }
++    pub const fn s32() -> Format { <i32 as IoFormat>::FORMAT }
++    pub const fn u32() -> Format { <u32 as IoFormat>::FORMAT }
++    pub const fn float() -> Format { <f32 as IoFormat>::FORMAT }
++    pub const fn float64() -> Format { <f64 as IoFormat>::FORMAT }
+ 
+-    #[cfg(target_endian = "little")] pub fn s24() -> Format { Format::S24LE }
+-    #[cfg(target_endian = "big")] pub fn s24() -> Format { Format::S24BE }
++    #[cfg(target_endian = "little")] pub const fn s24() -> Format { Format::S24LE }
++    #[cfg(target_endian = "big")] pub const fn s24() -> Format { Format::S24BE }
+ 
+-    #[cfg(target_endian = "little")] pub fn u24() -> Format { Format::U24LE }
+-    #[cfg(target_endian = "big")] pub fn u24() -> Format { Format::U24BE }
++    #[cfg(target_endian = "little")] pub const fn u24() -> Format { Format::U24LE }
++    #[cfg(target_endian = "big")] pub const fn u24() -> Format { Format::U24BE }
+ 
+-    #[cfg(target_endian = "little")] pub fn iec958_subframe() -> Format { Format::IEC958SubframeLE }
+-    #[cfg(target_endian = "big")] pub fn iec958_subframe() -> Format { Format::IEC958SubframeBE }
++    #[cfg(target_endian = "little")] pub const fn iec958_subframe() -> Format { Format::IEC958SubframeLE }
++    #[cfg(target_endian = "big")] pub const fn iec958_subframe() -> Format { Format::IEC958SubframeBE }
+ }
+ 
+ 
+@@ -769,6 +769,15 @@ impl<'a> HwParams<'a> {
+         unsafe { alsa::snd_pcm_hw_params_can_resume(self.0) != 0 }
+     }
+ 
++    /// Returns true if the alsa stream supports the provided `AudioTstampType`, false if not.
++    ///
++    /// This function should only be called when the configuration space contains a single
++    /// configuration. Call `PCM::hw_params` to choose a single configuration from the
++    /// configuration space.
++    pub fn supports_audio_ts_type(&self, type_: AudioTstampType) -> bool {
++        unsafe { alsa::snd_pcm_hw_params_supports_audio_ts_type(self.0, type_ as libc::c_int) != 0 }
++    }
++
+     pub fn dump(&self, o: &mut Output) -> Result<()> {
+         acheck!(snd_pcm_hw_params_dump(self.0, super::io::output_handle(o))).map(|_| ())
+     }
+@@ -923,6 +932,47 @@ impl Status {
+     }
+ }
+ 
++/// Builder for [`Status`].
++///
++/// Allows setting the audio timestamp configuration before retrieving the
++/// status from the stream.
++pub struct StatusBuilder(Status);
++
++impl StatusBuilder {
++    pub fn new() -> Self {
++        StatusBuilder(Status::new())
++    }
++
++    pub fn audio_htstamp_config(
++        self,
++        type_requested: AudioTstampType,
++        report_delay: bool,
++    ) -> Self {
++        let mut cfg: alsa::snd_pcm_audio_tstamp_config_t = unsafe { std::mem::zeroed() };
++        cfg.set_type_requested(type_requested as _);
++        cfg.set_report_delay(report_delay as _);
++        unsafe { alsa::snd_pcm_status_set_audio_htstamp_config(self.0.ptr(), &mut cfg) };
++        self
++    }
++
++    pub fn build(self, pcm: &PCM) -> Result<Status> {
++        acheck!(snd_pcm_status(pcm.0, self.0.ptr())).map(|_| self.0)
++    }
++}
++
++alsa_enum!(
++    #[non_exhaustive]
++    /// [SND_PCM_AUDIO_TSTAMP_TYPE_xxx](http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html) constants
++    AudioTstampType, ALL_AUDIO_TSTAMP_TYPES[6],
++
++    Compat = SND_PCM_AUDIO_TSTAMP_TYPE_COMPAT,
++    Default = SND_PCM_AUDIO_TSTAMP_TYPE_DEFAULT,
++    Link = SND_PCM_AUDIO_TSTAMP_TYPE_LINK,
++    LinkAbsolute = SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ABSOLUTE,
++    LinkEstimated = SND_PCM_AUDIO_TSTAMP_TYPE_LINK_ESTIMATED,
++    LinkSynchronized = SND_PCM_AUDIO_TSTAMP_TYPE_LINK_SYNCHRONIZED,
++);
++
+ #[test]
+ fn info_from_default() {
+     use std::ffi::CString;
+diff --git a/third_party/rust/bitflags/.cargo-checksum.json b/third_party/rust/bitflags/.cargo-checksum.json
+index 7e8d470b53a37..a8b031c6517a2 100644
+--- a/third_party/rust/bitflags/.cargo-checksum.json
++++ b/third_party/rust/bitflags/.cargo-checksum.json
+@@ -1 +1 @@
+-{"files":{"CHANGELOG.md":"d362fc1fccaaf4d421bcf0fe8b80ddb4f625dade0c1ee52d08bd0b95509a49d1","CODE_OF_CONDUCT.md":"42634d0f6d922f49857175af991802822f7f920487aefa2ee250a50d12251a66","Cargo.toml":"87aced7532a7974eb37ab5fe6037f0abafc36d6b2d74891ecd2bf2f14f50d11e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"baa8604f8afb34fd93b9c79729daafb884dedcaf34023e4af8ad037d916061fd","src/example_generated.rs":"e43eb59e90f317f38d436670a6067d2fd9eb35fb319fe716184e4a04e24ed1b2","src/lib.rs":"e6477688535ee326d27238aeedc9cb4320ac35b9d17a4deda09e0587b0ccdbd4","tests/basic.rs":"146f1cbf6279bc609242cd3349f29cb21b41294f5e4921875f5ec95bd83529a2","tests/compile-fail/impls/copy.rs":"b791371237ddc75a7c04d2130e03b462c9c00a80dca08bd45aa97433d9c0d13a","tests/compile-fail/impls/copy.stderr.beta":"77d83484ce221d4b6ff2f7de843929a452d779fcfff428122710dd8218c298e3","tests/compile-fail/i
 mpls/eq.rs":"0cee8b9e07d537890e0189710293b53972d0fab63c09366f33c391065afafa99","tests/compile-fail/impls/eq.stderr.beta":"381fc6143d45ce76d7cecc47aa59cb69fe5e79c0b60a4a85d5c6163b400b3cc7","tests/compile-fail/non_integer_base/all_defined.rs":"95e14cad9e94560262f2862c3c01865ac30369b69da1001b0e7285cb55e6cb75","tests/compile-fail/non_integer_base/all_defined.stderr.beta":"1760739a276690903bb03844025587d37939f5dfcbfab309db3c86f32bdbf748","tests/compile-fail/non_integer_base/all_missing.rs":"b3d9da619d23213731ba2581aa7999c796c3c79aaf4f0ee6b11ceec08a11537f","tests/compile-fail/non_integer_base/all_missing.stderr.beta":"37e102290d3867e175b21976be798939f294efb17580d5b51e7b17b590d55132","tests/compile-fail/visibility/private_field.rs":"38e4d3fe6471829360d12c8d09b097f6a21aa93fb51eac3b215d96bdae23316b","tests/compile-fail/visibility/private_field.stderr.beta":"5aa24a3ebb39326f31927721c5017b8beb66c3e501fb865a3fa814c9763bfa0f","tests/compile-fail/visibility/private_flags.rs":"2ce4235802aa4e9c96c4
 e77d9e31d8401ef58dcda4741325184f0764ab1fe393","tests/compile-fail/visibility/private_flags.stderr.beta":"f3eb9f7baf2689258f3519ff7ee5c6ec3c237264ebcfe63f40c40f2023e5022f","tests/compile-fail/visibility/pub_const.rs":"8f813a97ac518c5ea8ac65b184101912452384afaf7b8d6c5e62f8370eca3c0a","tests/compile-fail/visibility/pub_const.stderr.beta":"823976ae1794d7f5372e2ec9aabba497e7bb88004722904c38da342ed98e8962","tests/compile-pass/impls/convert.rs":"88fe80bfb9cd5779f0e1d92c9ec02a8b6bb67e334c07f2309e9c0ba5ef776eb0","tests/compile-pass/impls/default.rs":"c508f9a461691f44b45142fa5ad599f02326e1de4c0cbca6c0593f4652eba109","tests/compile-pass/impls/inherent_methods.rs":"ecc26388e9a394bfa7a5bb69a5d621ab3d4d1e53f28f657bb8e78fe79f437913","tests/compile-pass/redefinition/core.rs":"ff5b6e72f87acc6ebb12405d3c0f6e3fa62e669933656a454bb63b30ea44179c","tests/compile-pass/redefinition/stringify.rs":"1edbce42b900c14425d7ffa14e83e165ebe452d7dccd8c0a8a821bdec64f5c93","tests/compile-pass/repr/c.rs":"6fda17f7c2edfc
 d155314579e83d0fc8a16209e400f1f9a5ca77bd9a799041f2","tests/compile-pass/repr/transparent.rs":"6cdc87a2137d8a4e0c8ce9b6cba83c82255f8ea125951bf614418685600489ce","tests/compile-pass/visibility/bits_field.rs":"1f3e5ba5a047440066a9f6bf7b7af33f5b06f6b1da3dd9af6886168199a7ea0a","tests/compile-pass/visibility/pub_in.rs":"e95312ff60966d42ec4bc00225507895a9b8ec24056ce6a9edd9145be35d730f","tests/compile.rs":"f27c67a7dd183ca30efea1b6e0880e3469a6dd63b92b1fd711c082df182c9eec"},"package":"bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"}
+\ No newline at end of file
++{"files":{"CHANGELOG.md":"00224cc8d292567bdd212c36db66a1f662cd2e6c58e947900680234937e288a9","CODE_OF_CONDUCT.md":"42634d0f6d922f49857175af991802822f7f920487aefa2ee250a50d12251a66","Cargo.toml":"abacd42e33056c16008ab8eefd16eb2403cbc3393f8a6ed352a9a39d945ad3a5","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"6b236f8b62c82f189fabce0756e01a2c0ab1f32cb84cad9ff3c96b2ce5282bda","build.rs":"8923f38056f859b30aa9022980bb517755cbef57e1b09c34b33b27eb03b0626c","src/example_generated.rs":"e43eb59e90f317f38d436670a6067d2fd9eb35fb319fe716184e4a04e24ed1b2","src/lib.rs":"bd4e44ac35831c75af8815ba3a11ee1659afe0f72ce9c5f638a66bf50aa23d2a"},"package":"cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"}
+\ No newline at end of file
+diff --git a/third_party/rust/bitflags/CHANGELOG.md b/third_party/rust/bitflags/CHANGELOG.md
+index 12fea1673ac30..0d4910153d909 100644
+--- a/third_party/rust/bitflags/CHANGELOG.md
++++ b/third_party/rust/bitflags/CHANGELOG.md
+@@ -1,60 +1,3 @@
+-# 1.3.2
+-
+-- Allow `non_snake_case` in generated flags types ([#256])
+-
+-[#252]: https://github.com/bitflags/bitflags/pull/256
+-
+-# 1.3.1
+-
+-- Revert unconditional `#[repr(transparent)]` ([#252])
+-
+-[#252]: https://github.com/bitflags/bitflags/pull/252
+-
+-# 1.3.0 (yanked)
+-
+-- Add `#[repr(transparent)]` ([#187])
+-
+-- End `empty` doc comment with full stop ([#202])
+-
+-- Fix typo in crate root docs ([#206])
+-
+-- Document from_bits_unchecked unsafety ([#207])
+-
+-- Let `is_all` ignore extra bits ([#211])
+-
+-- Allows empty flag definition ([#225])
+-
+-- Making crate accessible from std ([#227])
+-
+-- Make `from_bits` a const fn ([#229])
+-
+-- Allow multiple bitflags structs in one macro invocation ([#235])
+-
+-- Add named functions to perform set operations ([#244])
+-
+-- Fix typos in method docs ([#245])
+-
+-- Modernization of the `bitflags` macro to take advantage of newer features and 2018 idioms ([#246])
+-
+-- Fix regression (in an unreleased feature) and simplify tests ([#247])
+-
+-- Use `Self` and fix bug when overriding `stringify!` ([#249])
+-
+-[#187]: https://github.com/bitflags/bitflags/pull/187
+-[#202]: https://github.com/bitflags/bitflags/pull/202
+-[#206]: https://github.com/bitflags/bitflags/pull/206
+-[#207]: https://github.com/bitflags/bitflags/pull/207
+-[#211]: https://github.com/bitflags/bitflags/pull/211
+-[#225]: https://github.com/bitflags/bitflags/pull/225
+-[#227]: https://github.com/bitflags/bitflags/pull/227
+-[#229]: https://github.com/bitflags/bitflags/pull/229
+-[#235]: https://github.com/bitflags/bitflags/pull/235
+-[#244]: https://github.com/bitflags/bitflags/pull/244
+-[#245]: https://github.com/bitflags/bitflags/pull/245
+-[#246]: https://github.com/bitflags/bitflags/pull/246
+-[#247]: https://github.com/bitflags/bitflags/pull/247
+-[#249]: https://github.com/bitflags/bitflags/pull/249
+-
+ # 1.2.1
+ 
+ - Remove extraneous `#[inline]` attributes ([#194])
+diff --git a/third_party/rust/bitflags/Cargo.toml b/third_party/rust/bitflags/Cargo.toml
+index 9d54c725a1c5d..b803644d44753 100644
+--- a/third_party/rust/bitflags/Cargo.toml
++++ b/third_party/rust/bitflags/Cargo.toml
+@@ -11,11 +11,11 @@
+ # will likely look very different (and much more reasonable)
+ 
+ [package]
+-edition = "2018"
+ name = "bitflags"
+-version = "1.3.2"
++version = "1.2.1"
+ authors = ["The Rust Project Developers"]
+-exclude = ["bors.toml"]
++build = "build.rs"
++exclude = [".travis.yml", "appveyor.yml", "bors.toml"]
+ description = "A macro to generate structures which behave like bitflags.\n"
+ homepage = "https://github.com/bitflags/bitflags"
+ documentation = "https://docs.rs/bitflags"
+@@ -26,33 +26,9 @@ license = "MIT/Apache-2.0"
+ repository = "https://github.com/bitflags/bitflags"
+ [package.metadata.docs.rs]
+ features = ["example_generated"]
+-[dependencies.compiler_builtins]
+-version = "0.1.2"
+-optional = true
+-
+-[dependencies.core]
+-version = "1.0.0"
+-optional = true
+-package = "rustc-std-workspace-core"
+-[dev-dependencies.rustversion]
+-version = "1.0"
+-
+-[dev-dependencies.serde]
+-version = "1.0"
+-
+-[dev-dependencies.serde_derive]
+-version = "1.0"
+-
+-[dev-dependencies.serde_json]
+-version = "1.0"
+-
+-[dev-dependencies.trybuild]
+-version = "1.0"
+-
+-[dev-dependencies.walkdir]
+-version = "2.3"
+ 
+ [features]
+ default = []
+ example_generated = []
+-rustc-dep-of-std = ["core", "compiler_builtins"]
++[badges.travis-ci]
++repository = "bitflags/bitflags"
+diff --git a/third_party/rust/bitflags/README.md b/third_party/rust/bitflags/README.md
+index 0da0f853661b0..df12934c3e28a 100644
+--- a/third_party/rust/bitflags/README.md
++++ b/third_party/rust/bitflags/README.md
+@@ -1,10 +1,11 @@
+ bitflags
+ ========
+ 
+-[![Rust](https://github.com/bitflags/bitflags/workflows/Rust/badge.svg)](https://github.com/bitflags/bitflags/actions)
++[![Build Status](https://travis-ci.com/bitflags/bitflags.svg?branch=master)](https://travis-ci.com/bitflags/bitflags)
+ [![Join the chat at https://gitter.im/bitflags/Lobby](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/bitflags/Lobby?utm_source=badge&utm_medium=badge&utm_content=badge)
+ [![Latest version](https://img.shields.io/crates/v/bitflags.svg)](https://crates.io/crates/bitflags)
+ [![Documentation](https://docs.rs/bitflags/badge.svg)](https://docs.rs/bitflags)
++![Minimum rustc version](https://img.shields.io/badge/rustc-1.20+-yellow.svg)
+ ![License](https://img.shields.io/crates/l/bitflags.svg)
+ 
+ A Rust macro to generate structures which behave like a set of bitflags
+@@ -18,15 +19,16 @@ Add this to your `Cargo.toml`:
+ 
+ ```toml
+ [dependencies]
+-bitflags = "1.3"
++bitflags = "1.0"
+ ```
+ 
+-and this to your source code:
++and this to your crate root:
+ 
+ ```rust
+-use bitflags::bitflags;
++#[macro_use]
++extern crate bitflags;
+ ```
+ 
+ ## Rust Version Support
+ 
+-The minimum supported Rust version is 1.46 due to use of associated constants and const functions.
++The minimum supported Rust version is 1.20 due to use of associated constants.
+diff --git a/third_party/rust/bitflags/build.rs b/third_party/rust/bitflags/build.rs
+new file mode 100644
+index 0000000000000..985757a6f6126
+--- /dev/null
++++ b/third_party/rust/bitflags/build.rs
+@@ -0,0 +1,44 @@
++use std::env;
++use std::process::Command;
++use std::str::{self, FromStr};
++
++fn main(){
++    let minor = match rustc_minor_version() {
++        Some(minor) => minor,
++        None => return,
++    };
++
++    // const fn stabilized in Rust 1.31:
++    if minor >= 31 {
++        println!("cargo:rustc-cfg=bitflags_const_fn");
++    }
++}
++
++fn rustc_minor_version() -> Option<u32> {
++    let rustc = match env::var_os("RUSTC") {
++        Some(rustc) => rustc,
++        None => return None,
++    };
++
++    let output = match Command::new(rustc).arg("--version").output() {
++        Ok(output) => output,
++        Err(_) => return None,
++    };
++
++    let version = match str::from_utf8(&output.stdout) {
++        Ok(version) => version,
++        Err(_) => return None,
++    };
++
++    let mut pieces = version.split('.');
++    if pieces.next() != Some("rustc 1") {
++        return None;
++    }
++
++    let next = match pieces.next() {
++        Some(next) => next,
++        None => return None,
++    };
++
++    u32::from_str(next).ok()
++}
+\ No newline at end of file
+diff --git a/third_party/rust/bitflags/src/lib.rs b/third_party/rust/bitflags/src/lib.rs
+index 935e432f1701e..3929b02ac10d7 100644
+--- a/third_party/rust/bitflags/src/lib.rs
++++ b/third_party/rust/bitflags/src/lib.rs
+@@ -11,14 +11,15 @@
+ //! A typesafe bitmask flag generator useful for sets of C-style bitmask flags.
+ //! It can be used for creating typesafe wrappers around C APIs.
+ //!
+-//! The `bitflags!` macro generates `struct`s that manage a set of flags. The
++//! The `bitflags!` macro generates a `struct` that manages a set of flags. The
+ //! flags should only be defined for integer types, otherwise unexpected type
+ //! errors may occur at compile time.
+ //!
+ //! # Example
+ //!
+ //! ```
+-//! use bitflags::bitflags;
++//! #[macro_use]
++//! extern crate bitflags;
+ //!
+ //! bitflags! {
+ //!     struct Flags: u32 {
+@@ -46,9 +47,10 @@
+ //! implementations:
+ //!
+ //! ```
+-//! use std::fmt;
++//! #[macro_use]
++//! extern crate bitflags;
+ //!
+-//! use bitflags::bitflags;
++//! use std::fmt;
+ //!
+ //! bitflags! {
+ //!     struct Flags: u32 {
+@@ -82,19 +84,21 @@
+ //!
+ //! # Visibility
+ //!
+-//! The generated structs and their associated flag constants are not exported
++//! The generated struct and its associated flag constants are not exported
+ //! out of the current module by default. A definition can be exported out of
+-//! the current module by adding `pub` before `struct`:
++//! the current module by adding `pub` before `flags`:
+ //!
+ //! ```
+-//! mod example {
+-//!     use bitflags::bitflags;
++//! #[macro_use]
++//! extern crate bitflags;
+ //!
++//! mod example {
+ //!     bitflags! {
+ //!         pub struct Flags1: u32 {
+ //!             const A = 0b00000001;
+ //!         }
+-//!
++//!     }
++//!     bitflags! {
+ //! #       pub
+ //!         struct Flags2: u32 {
+ //!             const B = 0b00000010;
+@@ -110,44 +114,26 @@
+ //!
+ //! # Attributes
+ //!
+-//! Attributes can be attached to the generated `struct`s by placing them
+-//! before the `struct` keyword.
+-//!
+-//! ## Representations
+-//!
+-//! It's valid to add a `#[repr(C)]` or `#[repr(transparent)]` attribute to a type
+-//! generated by `bitflags!`. In these cases, the type is guaranteed to be a newtype.
+-//!
+-//! ```
+-//! use bitflags::bitflags;
+-//!
+-//! bitflags! {
+-//!     #[repr(transparent)]
+-//!     struct Flags: u32 {
+-//!         const A = 0b00000001;
+-//!         const B = 0b00000010;
+-//!         const C = 0b00000100;
+-//!     }
+-//! }
+-//! ```
++//! Attributes can be attached to the generated `struct` by placing them
++//! before the `flags` keyword.
+ //!
+ //! # Trait implementations
+ //!
+ //! The `Copy`, `Clone`, `PartialEq`, `Eq`, `PartialOrd`, `Ord` and `Hash`
+-//! traits are automatically derived for the `struct`s using the `derive` attribute.
++//! traits automatically derived for the `struct` using the `derive` attribute.
+ //! Additional traits can be derived by providing an explicit `derive`
+-//! attribute on `struct`.
++//! attribute on `flags`.
+ //!
+-//! The `Extend` and `FromIterator` traits are implemented for the `struct`s,
++//! The `Extend` and `FromIterator` traits are implemented for the `struct`,
+ //! too: `Extend` adds the union of the instances of the `struct` iterated over,
+ //! while `FromIterator` calculates the union.
+ //!
+-//! The `Binary`, `Debug`, `LowerHex`, `Octal` and `UpperHex` traits are also
++//! The `Binary`, `Debug`, `LowerHex`, `Octal` and `UpperHex` trait is also
+ //! implemented by displaying the bits value of the internal struct.
+ //!
+ //! ## Operators
+ //!
+-//! The following operator traits are implemented for the generated `struct`s:
++//! The following operator traits are implemented for the generated `struct`:
+ //!
+ //! - `BitOr` and `BitOrAssign`: union
+ //! - `BitAnd` and `BitAndAssign`: intersection
+@@ -157,7 +143,7 @@
+ //!
+ //! # Methods
+ //!
+-//! The following methods are defined for the generated `struct`s:
++//! The following methods are defined for the generated `struct`:
+ //!
+ //! - `empty`: an empty set of flags
+ //! - `all`: the set of all defined flags
+@@ -173,34 +159,23 @@
+ //! - `is_empty`: `true` if no flags are currently stored
+ //! - `is_all`: `true` if currently set flags exactly equal all defined flags
+ //! - `intersects`: `true` if there are flags common to both `self` and `other`
+-//! - `contains`: `true` if all of the flags in `other` are contained within `self`
++//! - `contains`: `true` all of the flags in `other` are contained within `self`
+ //! - `insert`: inserts the specified flags in-place
+ //! - `remove`: removes the specified flags in-place
+ //! - `toggle`: the specified flags will be inserted if not present, and removed
+ //!             if they are.
+ //! - `set`: inserts or removes the specified flags depending on the passed value
+-//! - `intersection`: returns a new set of flags, containing only the flags present
+-//!                   in both `self` and `other` (the argument to the function).
+-//! - `union`: returns a new set of flags, containing any flags present in
+-//!            either `self` or `other` (the argument to the function).
+-//! - `difference`: returns a new set of flags, containing all flags present in
+-//!                 `self` without any of the flags present in `other` (the
+-//!                 argument to the function).
+-//! - `symmetric_difference`: returns a new set of flags, containing all flags
+-//!                           present in either `self` or `other` (the argument
+-//!                           to the function), but not both.
+-//! - `complement`: returns a new set of flags, containing all flags which are
+-//!                 not set in `self`, but which are allowed for this type.
+ //!
+ //! ## Default
+ //!
+-//! The `Default` trait is not automatically implemented for the generated structs.
++//! The `Default` trait is not automatically implemented for the generated struct.
+ //!
+ //! If your default value is equal to `0` (which is the same value as calling `empty()`
+ //! on the generated struct), you can simply derive `Default`:
+ //!
+ //! ```
+-//! use bitflags::bitflags;
++//! #[macro_use]
++//! extern crate bitflags;
+ //!
+ //! bitflags! {
+ //!     // Results in default value with bits: 0
+@@ -221,7 +196,8 @@
+ //! If your default value is not equal to `0` you need to implement `Default` yourself:
+ //!
+ //! ```
+-//! use bitflags::bitflags;
++//! #[macro_use]
++//! extern crate bitflags;
+ //!
+ //! bitflags! {
+ //!     struct Flags: u32 {
+@@ -249,7 +225,8 @@
+ //! Flags with a value equal to zero will have some strange behavior that one should be aware of.
+ //!
+ //! ```
+-//! use bitflags::bitflags;
++//! #[macro_use]
++//! extern crate bitflags;
+ //!
+ //! bitflags! {
+ //!     struct Flags: u32 {
+@@ -272,23 +249,28 @@
+ //!     assert!(none.is_empty());
+ //! }
+ //! ```
+-//!
+-//! Users should generally avoid defining a flag with a value of zero.
+ 
+-#![cfg_attr(not(test), no_std)]
+-#![doc(html_root_url = "https://docs.rs/bitflags/1.3.2")]
++#![no_std]
++#![doc(html_root_url = "https://docs.rs/bitflags/1.2.1")]
++
++#[cfg(test)]
++#[macro_use]
++extern crate std;
+ 
++// Re-export libcore using an alias so that the macros can work without
++// requiring `extern crate core` downstream.
+ #[doc(hidden)]
+ pub extern crate core as _core;
+ 
+-/// The macro used to generate the flag structures.
++/// The macro used to generate the flag structure.
+ ///
+ /// See the [crate level docs](../bitflags/index.html) for complete documentation.
+ ///
+ /// # Example
+ ///
+ /// ```
+-/// use bitflags::bitflags;
++/// #[macro_use]
++/// extern crate bitflags;
+ ///
+ /// bitflags! {
+ ///     struct Flags: u32 {
+@@ -313,9 +295,10 @@ pub extern crate core as _core;
+ /// implementations:
+ ///
+ /// ```
+-/// use std::fmt;
++/// #[macro_use]
++/// extern crate bitflags;
+ ///
+-/// use bitflags::bitflags;
++/// use std::fmt;
+ ///
+ /// bitflags! {
+ ///     struct Flags: u32 {
+@@ -350,18 +333,78 @@ pub extern crate core as _core;
+ macro_rules! bitflags {
+     (
+         $(#[$outer:meta])*
+-        $vis:vis struct $BitFlags:ident: $T:ty {
++        pub struct $BitFlags:ident: $T:ty {
++            $(
++                $(#[$inner:ident $($args:tt)*])*
++                const $Flag:ident = $value:expr;
++            )+
++        }
++    ) => {
++        __bitflags! {
++            $(#[$outer])*
++            (pub) $BitFlags: $T {
++                $(
++                    $(#[$inner $($args)*])*
++                    $Flag = $value;
++                )+
++            }
++        }
++    };
++    (
++        $(#[$outer:meta])*
++        struct $BitFlags:ident: $T:ty {
++            $(
++                $(#[$inner:ident $($args:tt)*])*
++                const $Flag:ident = $value:expr;
++            )+
++        }
++    ) => {
++        __bitflags! {
++            $(#[$outer])*
++            () $BitFlags: $T {
++                $(
++                    $(#[$inner $($args)*])*
++                    $Flag = $value;
++                )+
++            }
++        }
++    };
++    (
++        $(#[$outer:meta])*
++        pub ($($vis:tt)+) struct $BitFlags:ident: $T:ty {
+             $(
+                 $(#[$inner:ident $($args:tt)*])*
+                 const $Flag:ident = $value:expr;
+-            )*
++            )+
++        }
++    ) => {
++        __bitflags! {
++            $(#[$outer])*
++            (pub ($($vis)+)) $BitFlags: $T {
++                $(
++                    $(#[$inner $($args)*])*
++                    $Flag = $value;
++                )+
++            }
+         }
++    };
++}
+ 
+-        $($t:tt)*
++#[macro_export(local_inner_macros)]
++#[doc(hidden)]
++macro_rules! __bitflags {
++    (
++        $(#[$outer:meta])*
++        ($($vis:tt)*) $BitFlags:ident: $T:ty {
++            $(
++                $(#[$inner:ident $($args:tt)*])*
++                $Flag:ident = $value:expr;
++            )+
++        }
+     ) => {
+         $(#[$outer])*
+         #[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
+-        $vis struct $BitFlags {
++        $($vis)* struct $BitFlags {
+             bits: $T,
+         }
+ 
+@@ -370,52 +413,63 @@ macro_rules! bitflags {
+                 $(
+                     $(#[$inner $($args)*])*
+                     $Flag = $value;
+-                )*
++                )+
+             }
+         }
++    };
++}
+ 
+-        bitflags! {
+-            $($t)*
+-        }
++#[macro_export(local_inner_macros)]
++#[doc(hidden)]
++#[cfg(bitflags_const_fn)]
++macro_rules! __fn_bitflags {
++    (
++        $(# $attr_args:tt)*
++        const fn $($item:tt)*
++    ) => {
++        $(# $attr_args)*
++        const fn $($item)*
++    };
++    (
++        $(# $attr_args:tt)*
++        pub const fn $($item:tt)*
++    ) => {
++        $(# $attr_args)*
++        pub const fn $($item)*
++    };
++    (
++        $(# $attr_args:tt)*
++        pub const unsafe fn $($item:tt)*
++    ) => {
++        $(# $attr_args)*
++        pub const unsafe fn $($item)*
+     };
+-    () => {};
+ }
+ 
+-// A helper macro to implement the `all` function.
+ #[macro_export(local_inner_macros)]
+ #[doc(hidden)]
+-macro_rules! __impl_all_bitflags {
++#[cfg(not(bitflags_const_fn))]
++macro_rules! __fn_bitflags {
+     (
+-        $BitFlags:ident: $T:ty {
+-            $(
+-                $(#[$attr:ident $($args:tt)*])*
+-                $Flag:ident = $value:expr;
+-            )+
+-        }
++        $(# $attr_args:tt)*
++        const fn $($item:tt)*
+     ) => {
+-        // See `Debug::fmt` for why this approach is taken.
+-        #[allow(non_snake_case)]
+-        trait __BitFlags {
+-            $(
+-                const $Flag: $T = 0;
+-            )+
+-        }
+-        #[allow(non_snake_case)]
+-        impl __BitFlags for $BitFlags {
+-            $(
+-                __impl_bitflags! {
+-                    #[allow(deprecated)]
+-                    $(? #[$attr $($args)*])*
+-                    const $Flag: $T = Self::$Flag.bits;
+-                }
+-            )+
+-        }
+-        Self { bits: $(<Self as __BitFlags>::$Flag)|+ }
++        $(# $attr_args)*
++        fn $($item)*
++    };
++    (
++        $(# $attr_args:tt)*
++        pub const fn $($item:tt)*
++    ) => {
++        $(# $attr_args)*
++        pub fn $($item)*
+     };
+     (
+-        $BitFlags:ident: $T:ty { }
++        $(# $attr_args:tt)*
++        pub const unsafe fn $($item:tt)*
+     ) => {
+-        Self { bits: 0 }
++        $(# $attr_args)*
++        pub unsafe fn $($item)*
+     };
+ }
+ 
+@@ -427,7 +481,7 @@ macro_rules! __impl_bitflags {
+             $(
+                 $(#[$attr:ident $($args:tt)*])*
+                 $Flag:ident = $value:expr;
+-            )*
++            )+
+         }
+     ) => {
+         impl $crate::_core::fmt::Debug for $BitFlags {
+@@ -445,12 +499,11 @@ macro_rules! __impl_bitflags {
+                     $(
+                         #[inline]
+                         fn $Flag(&self) -> bool { false }
+-                    )*
++                    )+
+                 }
+ 
+                 // Conditionally override the check for just those flags that
+                 // are not #[cfg]ed away.
+-                #[allow(non_snake_case)]
+                 impl __BitFlags for $BitFlags {
+                     $(
+                         __impl_bitflags! {
+@@ -465,20 +518,20 @@ macro_rules! __impl_bitflags {
+                                 }
+                             }
+                         }
+-                    )*
++                    )+
+                 }
+ 
+                 let mut first = true;
+                 $(
+-                    if <Self as __BitFlags>::$Flag(self) {
++                    if <$BitFlags as __BitFlags>::$Flag(self) {
+                         if !first {
+                             f.write_str(" | ")?;
+                         }
+                         first = false;
+-                        f.write_str($crate::_core::stringify!($Flag))?;
++                        f.write_str(__bitflags_stringify!($Flag))?;
+                     }
+-                )*
+-                let extra_bits = self.bits & !Self::all().bits();
++                )+
++                let extra_bits = self.bits & !$BitFlags::all().bits();
+                 if extra_bits != 0 {
+                     if !first {
+                         f.write_str(" | ")?;
+@@ -518,295 +571,227 @@ macro_rules! __impl_bitflags {
+         impl $BitFlags {
+             $(
+                 $(#[$attr $($args)*])*
+-                pub const $Flag: Self = Self { bits: $value };
+-            )*
++                pub const $Flag: $BitFlags = $BitFlags { bits: $value };
++            )+
+ 
+-            /// Returns an empty set of flags.
+-            #[inline]
+-            pub const fn empty() -> Self {
+-                Self { bits: 0 }
++            __fn_bitflags! {
++                /// Returns an empty set of flags
++                #[inline]
++                pub const fn empty() -> $BitFlags {
++                    $BitFlags { bits: 0 }
++                }
+             }
+ 
+-            /// Returns the set containing all flags.
+-            #[inline]
+-            pub const fn all() -> Self {
+-                __impl_all_bitflags! {
+-                    $BitFlags: $T {
++            __fn_bitflags! {
++                /// Returns the set containing all flags.
++                #[inline]
++                pub const fn all() -> $BitFlags {
++                    // See `Debug::fmt` for why this approach is taken.
++                    #[allow(non_snake_case)]
++                    trait __BitFlags {
+                         $(
+-                            $(#[$attr $($args)*])*
+-                            $Flag = $value;
+-                        )*
++                            const $Flag: $T = 0;
++                        )+
+                     }
++                    impl __BitFlags for $BitFlags {
++                        $(
++                            __impl_bitflags! {
++                                #[allow(deprecated)]
++                                $(? #[$attr $($args)*])*
++                                const $Flag: $T = Self::$Flag.bits;
++                            }
++                        )+
++                    }
++                    $BitFlags { bits: $(<$BitFlags as __BitFlags>::$Flag)|+ }
+                 }
+             }
+ 
+-            /// Returns the raw value of the flags currently stored.
+-            #[inline]
+-            pub const fn bits(&self) -> $T {
+-                self.bits
++            __fn_bitflags! {
++                /// Returns the raw value of the flags currently stored.
++                #[inline]
++                pub const fn bits(&self) -> $T {
++                    self.bits
++                }
+             }
+ 
+             /// Convert from underlying bit representation, unless that
+             /// representation contains bits that do not correspond to a flag.
+             #[inline]
+-            pub const fn from_bits(bits: $T) -> $crate::_core::option::Option<Self> {
+-                if (bits & !Self::all().bits()) == 0 {
+-                    $crate::_core::option::Option::Some(Self { bits })
++            pub fn from_bits(bits: $T) -> $crate::_core::option::Option<$BitFlags> {
++                if (bits & !$BitFlags::all().bits()) == 0 {
++                    $crate::_core::option::Option::Some($BitFlags { bits })
+                 } else {
+                     $crate::_core::option::Option::None
+                 }
+             }
+ 
+-            /// Convert from underlying bit representation, dropping any bits
+-            /// that do not correspond to flags.
+-            #[inline]
+-            pub const fn from_bits_truncate(bits: $T) -> Self {
+-                Self { bits: bits & Self::all().bits }
++            __fn_bitflags! {
++                /// Convert from underlying bit representation, dropping any bits
++                /// that do not correspond to flags.
++                #[inline]
++                pub const fn from_bits_truncate(bits: $T) -> $BitFlags {
++                    $BitFlags { bits: bits & $BitFlags::all().bits }
++                }
+             }
+ 
+-            /// Convert from underlying bit representation, preserving all
+-            /// bits (even those not corresponding to a defined flag).
+-            ///
+-            /// # Safety
+-            ///
+-            /// The caller of the `bitflags!` macro can chose to allow or
+-            /// disallow extra bits for their bitflags type.
+-            ///
+-            /// The caller of `from_bits_unchecked()` has to ensure that
+-            /// all bits correspond to a defined flag or that extra bits
+-            /// are valid for this bitflags type.
+-            #[inline]
+-            pub const unsafe fn from_bits_unchecked(bits: $T) -> Self {
+-                Self { bits }
++            __fn_bitflags! {
++                /// Convert from underlying bit representation, preserving all
++                /// bits (even those not corresponding to a defined flag).
++                #[inline]
++                pub const unsafe fn from_bits_unchecked(bits: $T) -> $BitFlags {
++                    $BitFlags { bits }
++                }
+             }
+ 
+-            /// Returns `true` if no flags are currently stored.
+-            #[inline]
+-            pub const fn is_empty(&self) -> bool {
+-                self.bits() == Self::empty().bits()
++            __fn_bitflags! {
++                /// Returns `true` if no flags are currently stored.
++                #[inline]
++                pub const fn is_empty(&self) -> bool {
++                    self.bits() == $BitFlags::empty().bits()
++                }
+             }
+ 
+-            /// Returns `true` if all flags are currently set.
+-            #[inline]
+-            pub const fn is_all(&self) -> bool {
+-                Self::all().bits | self.bits == self.bits
++            __fn_bitflags! {
++                /// Returns `true` if all flags are currently set.
++                #[inline]
++                pub const fn is_all(&self) -> bool {
++                    self.bits == $BitFlags::all().bits
++                }
+             }
+ 
+-            /// Returns `true` if there are flags common to both `self` and `other`.
+-            #[inline]
+-            pub const fn intersects(&self, other: Self) -> bool {
+-                !(Self { bits: self.bits & other.bits}).is_empty()
++            __fn_bitflags! {
++                /// Returns `true` if there are flags common to both `self` and `other`.
++                #[inline]
++                pub const fn intersects(&self, other: $BitFlags) -> bool {
++                    !$BitFlags{ bits: self.bits & other.bits}.is_empty()
++                }
+             }
+ 
+-            /// Returns `true` if all of the flags in `other` are contained within `self`.
+-            #[inline]
+-            pub const fn contains(&self, other: Self) -> bool {
+-                (self.bits & other.bits) == other.bits
++            __fn_bitflags! {
++                /// Returns `true` all of the flags in `other` are contained within `self`.
++                #[inline]
++                pub const fn contains(&self, other: $BitFlags) -> bool {
++                    (self.bits & other.bits) == other.bits
++                }
+             }
+ 
+             /// Inserts the specified flags in-place.
+             #[inline]
+-            pub fn insert(&mut self, other: Self) {
++            pub fn insert(&mut self, other: $BitFlags) {
+                 self.bits |= other.bits;
+             }
+ 
+             /// Removes the specified flags in-place.
+             #[inline]
+-            pub fn remove(&mut self, other: Self) {
++            pub fn remove(&mut self, other: $BitFlags) {
+                 self.bits &= !other.bits;
+             }
+ 
+             /// Toggles the specified flags in-place.
+             #[inline]
+-            pub fn toggle(&mut self, other: Self) {
++            pub fn toggle(&mut self, other: $BitFlags) {
+                 self.bits ^= other.bits;
+             }
+ 
+             /// Inserts or removes the specified flags depending on the passed value.
+             #[inline]
+-            pub fn set(&mut self, other: Self, value: bool) {
++            pub fn set(&mut self, other: $BitFlags, value: bool) {
+                 if value {
+                     self.insert(other);
+                 } else {
+                     self.remove(other);
+                 }
+             }
+-
+-            /// Returns the intersection between the flags in `self` and
+-            /// `other`.
+-            ///
+-            /// Specifically, the returned set contains only the flags which are
+-            /// present in *both* `self` *and* `other`.
+-            ///
+-            /// This is equivalent to using the `&` operator (e.g.
+-            /// [`ops::BitAnd`]), as in `flags & other`.
+-            ///
+-            /// [`ops::BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html
+-            #[inline]
+-            #[must_use]
+-            pub const fn intersection(self, other: Self) -> Self {
+-                Self { bits: self.bits & other.bits }
+-            }
+-
+-            /// Returns the union of between the flags in `self` and `other`.
+-            ///
+-            /// Specifically, the returned set contains all flags which are
+-            /// present in *either* `self` *or* `other`, including any which are
+-            /// present in both (see [`Self::symmetric_difference`] if that
+-            /// is undesirable).
+-            ///
+-            /// This is equivalent to using the `|` operator (e.g.
+-            /// [`ops::BitOr`]), as in `flags | other`.
+-            ///
+-            /// [`ops::BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html
+-            #[inline]
+-            #[must_use]
+-            pub const fn union(self, other: Self) -> Self {
+-                Self { bits: self.bits | other.bits }
+-            }
+-
+-            /// Returns the difference between the flags in `self` and `other`.
+-            ///
+-            /// Specifically, the returned set contains all flags present in
+-            /// `self`, except for the ones present in `other`.
+-            ///
+-            /// It is also conceptually equivalent to the "bit-clear" operation:
+-            /// `flags & !other` (and this syntax is also supported).
+-            ///
+-            /// This is equivalent to using the `-` operator (e.g.
+-            /// [`ops::Sub`]), as in `flags - other`.
+-            ///
+-            /// [`ops::Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html
+-            #[inline]
+-            #[must_use]
+-            pub const fn difference(self, other: Self) -> Self {
+-                Self { bits: self.bits & !other.bits }
+-            }
+-
+-            /// Returns the [symmetric difference][sym-diff] between the flags
+-            /// in `self` and `other`.
+-            ///
+-            /// Specifically, the returned set contains the flags present which
+-            /// are present in `self` or `other`, but that are not present in
+-            /// both. Equivalently, it contains the flags present in *exactly
+-            /// one* of the sets `self` and `other`.
+-            ///
+-            /// This is equivalent to using the `^` operator (e.g.
+-            /// [`ops::BitXor`]), as in `flags ^ other`.
+-            ///
+-            /// [sym-diff]: https://en.wikipedia.org/wiki/Symmetric_difference
+-            /// [`ops::BitXor`]: https://doc.rust-lang.org/std/ops/trait.BitXor.html
+-            #[inline]
+-            #[must_use]
+-            pub const fn symmetric_difference(self, other: Self) -> Self {
+-                Self { bits: self.bits ^ other.bits }
+-            }
+-
+-            /// Returns the complement of this set of flags.
+-            ///
+-            /// Specifically, the returned set contains all the flags which are
+-            /// not set in `self`, but which are allowed for this type.
+-            ///
+-            /// Alternatively, it can be thought of as the set difference
+-            /// between [`Self::all()`] and `self` (e.g. `Self::all() - self`)
+-            ///
+-            /// This is equivalent to using the `!` operator (e.g.
+-            /// [`ops::Not`]), as in `!flags`.
+-            ///
+-            /// [`Self::all()`]: Self::all
+-            /// [`ops::Not`]: https://doc.rust-lang.org/std/ops/trait.Not.html
+-            #[inline]
+-            #[must_use]
+-            pub const fn complement(self) -> Self {
+-                Self::from_bits_truncate(!self.bits)
+-            }
+-
+         }
+ 
+         impl $crate::_core::ops::BitOr for $BitFlags {
+-            type Output = Self;
++            type Output = $BitFlags;
+ 
+             /// Returns the union of the two sets of flags.
+             #[inline]
+-            fn bitor(self, other: $BitFlags) -> Self {
+-                Self { bits: self.bits | other.bits }
++            fn bitor(self, other: $BitFlags) -> $BitFlags {
++                $BitFlags { bits: self.bits | other.bits }
+             }
+         }
+ 
+         impl $crate::_core::ops::BitOrAssign for $BitFlags {
++
+             /// Adds the set of flags.
+             #[inline]
+-            fn bitor_assign(&mut self, other: Self) {
++            fn bitor_assign(&mut self, other: $BitFlags) {
+                 self.bits |= other.bits;
+             }
+         }
+ 
+         impl $crate::_core::ops::BitXor for $BitFlags {
+-            type Output = Self;
++            type Output = $BitFlags;
+ 
+             /// Returns the left flags, but with all the right flags toggled.
+             #[inline]
+-            fn bitxor(self, other: Self) -> Self {
+-                Self { bits: self.bits ^ other.bits }
++            fn bitxor(self, other: $BitFlags) -> $BitFlags {
++                $BitFlags { bits: self.bits ^ other.bits }
+             }
+         }
+ 
+         impl $crate::_core::ops::BitXorAssign for $BitFlags {
++
+             /// Toggles the set of flags.
+             #[inline]
+-            fn bitxor_assign(&mut self, other: Self) {
++            fn bitxor_assign(&mut self, other: $BitFlags) {
+                 self.bits ^= other.bits;
+             }
+         }
+ 
+         impl $crate::_core::ops::BitAnd for $BitFlags {
+-            type Output = Self;
++            type Output = $BitFlags;
+ 
+             /// Returns the intersection between the two sets of flags.
+             #[inline]
+-            fn bitand(self, other: Self) -> Self {
+-                Self { bits: self.bits & other.bits }
++            fn bitand(self, other: $BitFlags) -> $BitFlags {
++                $BitFlags { bits: self.bits & other.bits }
+             }
+         }
+ 
+         impl $crate::_core::ops::BitAndAssign for $BitFlags {
++
+             /// Disables all flags disabled in the set.
+             #[inline]
+-            fn bitand_assign(&mut self, other: Self) {
++            fn bitand_assign(&mut self, other: $BitFlags) {
+                 self.bits &= other.bits;
+             }
+         }
+ 
+         impl $crate::_core::ops::Sub for $BitFlags {
+-            type Output = Self;
++            type Output = $BitFlags;
+ 
+             /// Returns the set difference of the two sets of flags.
+             #[inline]
+-            fn sub(self, other: Self) -> Self {
+-                Self { bits: self.bits & !other.bits }
++            fn sub(self, other: $BitFlags) -> $BitFlags {
++                $BitFlags { bits: self.bits & !other.bits }
+             }
+         }
+ 
+         impl $crate::_core::ops::SubAssign for $BitFlags {
++
+             /// Disables all flags enabled in the set.
+             #[inline]
+-            fn sub_assign(&mut self, other: Self) {
++            fn sub_assign(&mut self, other: $BitFlags) {
+                 self.bits &= !other.bits;
+             }
+         }
+ 
+         impl $crate::_core::ops::Not for $BitFlags {
+-            type Output = Self;
++            type Output = $BitFlags;
+ 
+             /// Returns the complement of this set of flags.
+             #[inline]
+-            fn not(self) -> Self {
+-                Self { bits: !self.bits } & Self::all()
++            fn not(self) -> $BitFlags {
++                $BitFlags { bits: !self.bits } & $BitFlags::all()
+             }
+         }
+ 
+         impl $crate::_core::iter::Extend<$BitFlags> for $BitFlags {
+-            fn extend<T: $crate::_core::iter::IntoIterator<Item=Self>>(&mut self, iterator: T) {
++            fn extend<T: $crate::_core::iter::IntoIterator<Item=$BitFlags>>(&mut self, iterator: T) {
+                 for item in iterator {
+                     self.insert(item)
+                 }
+@@ -814,7 +799,7 @@ macro_rules! __impl_bitflags {
+         }
+ 
+         impl $crate::_core::iter::FromIterator<$BitFlags> for $BitFlags {
+-            fn from_iter<T: $crate::_core::iter::IntoIterator<Item=Self>>(iterator: T) -> Self {
++            fn from_iter<T: $crate::_core::iter::IntoIterator<Item=$BitFlags>>(iterator: T) -> $BitFlags {
+                 let mut result = Self::empty();
+                 result.extend(iterator);
+                 result
+@@ -832,7 +817,7 @@ macro_rules! __impl_bitflags {
+     // Input:
+     //
+     //     ? #[cfg(feature = "advanced")]
+-    //     ? #[deprecated(note = "Use something else.")]
++    //     ? #[deprecated(note = "Use somthing else.")]
+     //     ? #[doc = r"High quality documentation."]
+     //     fn f() -> i32 { /* ... */ }
+     //
+@@ -887,7 +872,7 @@ macro_rules! __impl_bitflags {
+     // Input:
+     //
+     //     ? #[cfg(feature = "advanced")]
+-    //     ? #[deprecated(note = "Use something else.")]
++    //     ? #[deprecated(note = "Use somthing else.")]
+     //     ? #[doc = r"High quality documentation."]
+     //     const f: i32 { /* ... */ }
+     //
+@@ -931,6 +916,16 @@ macro_rules! __impl_bitflags {
+     };
+ }
+ 
++// Same as std::stringify but callable from __impl_bitflags, which needs to use
++// local_inner_macros so can only directly call macros from this crate.
++#[macro_export]
++#[doc(hidden)]
++macro_rules! __bitflags_stringify {
++    ($s:ident) => {
++        stringify!($s)
++    };
++}
++
+ #[cfg(feature = "example_generated")]
+ pub mod example_generated;
+ 
+@@ -944,7 +939,6 @@ mod tests {
+         #[doc = "> you are the easiest person to fool."]
+         #[doc = "> "]
+         #[doc = "> - Richard Feynman"]
+-        #[derive(Default)]
+         struct Flags: u32 {
+             const A = 0b00000001;
+             #[doc = "<pcwalton> macros are way better at generating code than trans is"]
+@@ -955,7 +949,9 @@ mod tests {
+             #[doc = "<strcat> wait what?"]
+             const ABC = Self::A.bits | Self::B.bits | Self::C.bits;
+         }
++    }
+ 
++    bitflags! {
+         struct _CfgFlags: u32 {
+             #[cfg(unix)]
+             const _CFG_A = 0b01;
+@@ -964,18 +960,17 @@ mod tests {
+             #[cfg(unix)]
+             const _CFG_C = Self::_CFG_A.bits | 0b10;
+         }
++    }
+ 
++    bitflags! {
+         struct AnotherSetOfFlags: i8 {
+             const ANOTHER_FLAG = -1_i8;
+         }
+-
+-        struct LongFlags: u32 {
+-            const LONG_A = 0b1111111111111111;
+-        }
+     }
+ 
+     bitflags! {
+-        struct EmptyFlags: u32 {
++        struct LongFlags: u32 {
++            const LONG_A = 0b1111111111111111;
+         }
+     }
+ 
+@@ -987,8 +982,6 @@ mod tests {
+ 
+         assert_eq!(AnotherSetOfFlags::empty().bits(), 0b00);
+         assert_eq!(AnotherSetOfFlags::ANOTHER_FLAG.bits(), !0_i8);
+-
+-        assert_eq!(EmptyFlags::empty().bits(), 0b00000000);
+     }
+ 
+     #[test]
+@@ -1003,9 +996,6 @@ mod tests {
+             AnotherSetOfFlags::from_bits(!0_i8),
+             Some(AnotherSetOfFlags::ANOTHER_FLAG)
+         );
+-
+-        assert_eq!(EmptyFlags::from_bits(0), Some(EmptyFlags::empty()));
+-        assert_eq!(EmptyFlags::from_bits(0b1), None);
+     }
+ 
+     #[test]
+@@ -1021,9 +1011,6 @@ mod tests {
+             AnotherSetOfFlags::from_bits_truncate(0_i8),
+             AnotherSetOfFlags::empty()
+         );
+-
+-        assert_eq!(EmptyFlags::from_bits_truncate(0), EmptyFlags::empty());
+-        assert_eq!(EmptyFlags::from_bits_truncate(0b1), EmptyFlags::empty());
+     }
+ 
+     #[test]
+@@ -1032,25 +1019,9 @@ mod tests {
+         assert_eq!(unsafe { Flags::from_bits_unchecked(0) }, Flags::empty());
+         assert_eq!(unsafe { Flags::from_bits_unchecked(0b1) }, Flags::A);
+         assert_eq!(unsafe { Flags::from_bits_unchecked(0b10) }, Flags::B);
+-
+-        assert_eq!(
+-            unsafe { Flags::from_bits_unchecked(0b11) },
+-            (Flags::A | Flags::B)
+-        );
+-        assert_eq!(
+-            unsafe { Flags::from_bits_unchecked(0b1000) },
+-            (extra | Flags::empty())
+-        );
+-        assert_eq!(
+-            unsafe { Flags::from_bits_unchecked(0b1001) },
+-            (extra | Flags::A)
+-        );
+-
+-        let extra = unsafe { EmptyFlags::from_bits_unchecked(0b1000) };
+-        assert_eq!(
+-            unsafe { EmptyFlags::from_bits_unchecked(0b1000) },
+-            (extra | EmptyFlags::empty())
+-        );
++        assert_eq!(unsafe { Flags::from_bits_unchecked(0b11) }, (Flags::A | Flags::B));
++        assert_eq!(unsafe { Flags::from_bits_unchecked(0b1000) }, (extra | Flags::empty()));
++        assert_eq!(unsafe { Flags::from_bits_unchecked(0b1001) }, (extra | Flags::A));
+     }
+ 
+     #[test]
+@@ -1060,9 +1031,6 @@ mod tests {
+         assert!(!Flags::ABC.is_empty());
+ 
+         assert!(!AnotherSetOfFlags::ANOTHER_FLAG.is_empty());
+-
+-        assert!(EmptyFlags::empty().is_empty());
+-        assert!(EmptyFlags::all().is_empty());
+     }
+ 
+     #[test]
+@@ -1071,15 +1039,7 @@ mod tests {
+         assert!(!Flags::A.is_all());
+         assert!(Flags::ABC.is_all());
+ 
+-        let extra = unsafe { Flags::from_bits_unchecked(0b1000) };
+-        assert!(!extra.is_all());
+-        assert!(!(Flags::A | extra).is_all());
+-        assert!((Flags::ABC | extra).is_all());
+-
+         assert!(AnotherSetOfFlags::ANOTHER_FLAG.is_all());
+-
+-        assert!(EmptyFlags::all().is_all());
+-        assert!(EmptyFlags::empty().is_all());
+     }
+ 
+     #[test]
+@@ -1121,8 +1081,6 @@ mod tests {
+         assert!(Flags::ABC.contains(e2));
+ 
+         assert!(AnotherSetOfFlags::ANOTHER_FLAG.contains(AnotherSetOfFlags::ANOTHER_FLAG));
+-
+-        assert!(EmptyFlags::empty().contains(EmptyFlags::empty()));
+     }
+ 
+     #[test]
+@@ -1183,188 +1141,6 @@ mod tests {
+         assert_eq!(e3, Flags::A | Flags::B | extra);
+     }
+ 
+-    #[test]
+-    fn test_set_ops_basic() {
+-        let ab = Flags::A.union(Flags::B);
+-        let ac = Flags::A.union(Flags::C);
+-        let bc = Flags::B.union(Flags::C);
+-        assert_eq!(ab.bits, 0b011);
+-        assert_eq!(bc.bits, 0b110);
+-        assert_eq!(ac.bits, 0b101);
+-
+-        assert_eq!(ab, Flags::B.union(Flags::A));
+-        assert_eq!(ac, Flags::C.union(Flags::A));
+-        assert_eq!(bc, Flags::C.union(Flags::B));
+-
+-        assert_eq!(ac, Flags::A | Flags::C);
+-        assert_eq!(bc, Flags::B | Flags::C);
+-        assert_eq!(ab.union(bc), Flags::ABC);
+-
+-        assert_eq!(ac, Flags::A | Flags::C);
+-        assert_eq!(bc, Flags::B | Flags::C);
+-
+-        assert_eq!(ac.union(bc), ac | bc);
+-        assert_eq!(ac.union(bc), Flags::ABC);
+-        assert_eq!(bc.union(ac), Flags::ABC);
+-
+-        assert_eq!(ac.intersection(bc), ac & bc);
+-        assert_eq!(ac.intersection(bc), Flags::C);
+-        assert_eq!(bc.intersection(ac), Flags::C);
+-
+-        assert_eq!(ac.difference(bc), ac - bc);
+-        assert_eq!(bc.difference(ac), bc - ac);
+-        assert_eq!(ac.difference(bc), Flags::A);
+-        assert_eq!(bc.difference(ac), Flags::B);
+-
+-        assert_eq!(bc.complement(), !bc);
+-        assert_eq!(bc.complement(), Flags::A);
+-        assert_eq!(ac.symmetric_difference(bc), Flags::A.union(Flags::B));
+-        assert_eq!(bc.symmetric_difference(ac), Flags::A.union(Flags::B));
+-    }
+-
+-    #[test]
+-    fn test_set_ops_const() {
+-        // These just test that these compile and don't cause use-site panics
+-        // (would be possible if we had some sort of UB)
+-        const INTERSECT: Flags = Flags::all().intersection(Flags::C);
+-        const UNION: Flags = Flags::A.union(Flags::C);
+-        const DIFFERENCE: Flags = Flags::all().difference(Flags::A);
+-        const COMPLEMENT: Flags = Flags::C.complement();
+-        const SYM_DIFFERENCE: Flags = UNION.symmetric_difference(DIFFERENCE);
+-        assert_eq!(INTERSECT, Flags::C);
+-        assert_eq!(UNION, Flags::A | Flags::C);
+-        assert_eq!(DIFFERENCE, Flags::all() - Flags::A);
+-        assert_eq!(COMPLEMENT, !Flags::C);
+-        assert_eq!(SYM_DIFFERENCE, (Flags::A | Flags::C) ^ (Flags::all() - Flags::A));
+-    }
+-
+-    #[test]
+-    fn test_set_ops_unchecked() {
+-        let extra = unsafe { Flags::from_bits_unchecked(0b1000) };
+-        let e1 = Flags::A.union(Flags::C).union(extra);
+-        let e2 = Flags::B.union(Flags::C);
+-        assert_eq!(e1.bits, 0b1101);
+-        assert_eq!(e1.union(e2), (Flags::ABC | extra));
+-        assert_eq!(e1.intersection(e2), Flags::C);
+-        assert_eq!(e1.difference(e2), Flags::A | extra);
+-        assert_eq!(e2.difference(e1), Flags::B);
+-        assert_eq!(e2.complement(), Flags::A);
+-        assert_eq!(e1.complement(), Flags::B);
+-        assert_eq!(e1.symmetric_difference(e2), Flags::A | Flags::B | extra); // toggle
+-    }
+-
+-    #[test]
+-    fn test_set_ops_exhaustive() {
+-        // Define a flag that contains gaps to help exercise edge-cases,
+-        // especially around "unknown" flags (e.g. ones outside of `all()`
+-        // `from_bits_unchecked`).
+-        // - when lhs and rhs both have different sets of unknown flags.
+-        // - unknown flags at both ends, and in the middle
+-        // - cases with "gaps".
+-        bitflags! {
+-            struct Test: u16 {
+-                // Intentionally no `A`
+-                const B = 0b000000010;
+-                // Intentionally no `C`
+-                const D = 0b000001000;
+-                const E = 0b000010000;
+-                const F = 0b000100000;
+-                const G = 0b001000000;
+-                // Intentionally no `H`
+-                const I = 0b100000000;
+-            }
+-        }
+-        let iter_test_flags =
+-            || (0..=0b111_1111_1111).map(|bits| unsafe { Test::from_bits_unchecked(bits) });
+-
+-        for a in iter_test_flags() {
+-            assert_eq!(
+-                a.complement(),
+-                Test::from_bits_truncate(!a.bits),
+-                "wrong result: !({:?})",
+-                a,
+-            );
+-            assert_eq!(a.complement(), !a, "named != op: !({:?})", a);
+-            for b in iter_test_flags() {
+-                // Check that the named operations produce the expected bitwise
+-                // values.
+-                assert_eq!(
+-                    a.union(b).bits,
+-                    a.bits | b.bits,
+-                    "wrong result: `{:?}` | `{:?}`",
+-                    a,
+-                    b,
+-                );
+-                assert_eq!(
+-                    a.intersection(b).bits,
+-                    a.bits & b.bits,
+-                    "wrong result: `{:?}` & `{:?}`",
+-                    a,
+-                    b,
+-                );
+-                assert_eq!(
+-                    a.symmetric_difference(b).bits,
+-                    a.bits ^ b.bits,
+-                    "wrong result: `{:?}` ^ `{:?}`",
+-                    a,
+-                    b,
+-                );
+-                assert_eq!(
+-                    a.difference(b).bits,
+-                    a.bits & !b.bits,
+-                    "wrong result: `{:?}` - `{:?}`",
+-                    a,
+-                    b,
+-                );
+-                // Note: Difference is checked as both `a - b` and `b - a`
+-                assert_eq!(
+-                    b.difference(a).bits,
+-                    b.bits & !a.bits,
+-                    "wrong result: `{:?}` - `{:?}`",
+-                    b,
+-                    a,
+-                );
+-                // Check that the named set operations are equivalent to the
+-                // bitwise equivalents
+-                assert_eq!(a.union(b), a | b, "named != op: `{:?}` | `{:?}`", a, b,);
+-                assert_eq!(
+-                    a.intersection(b),
+-                    a & b,
+-                    "named != op: `{:?}` & `{:?}`",
+-                    a,
+-                    b,
+-                );
+-                assert_eq!(
+-                    a.symmetric_difference(b),
+-                    a ^ b,
+-                    "named != op: `{:?}` ^ `{:?}`",
+-                    a,
+-                    b,
+-                );
+-                assert_eq!(a.difference(b), a - b, "named != op: `{:?}` - `{:?}`", a, b,);
+-                // Note: Difference is checked as both `a - b` and `b - a`
+-                assert_eq!(b.difference(a), b - a, "named != op: `{:?}` - `{:?}`", b, a,);
+-                // Verify that the operations which should be symmetric are
+-                // actually symmetric.
+-                assert_eq!(a.union(b), b.union(a), "asymmetry: `{:?}` | `{:?}`", a, b,);
+-                assert_eq!(
+-                    a.intersection(b),
+-                    b.intersection(a),
+-                    "asymmetry: `{:?}` & `{:?}`",
+-                    a,
+-                    b,
+-                );
+-                assert_eq!(
+-                    a.symmetric_difference(b),
+-                    b.symmetric_difference(a),
+-                    "asymmetry: `{:?}` ^ `{:?}`",
+-                    a,
+-                    b,
+-                );
+-            }
+-        }
+-    }
+-
+     #[test]
+     fn test_set() {
+         let mut e1 = Flags::A | Flags::C;
+@@ -1392,6 +1168,8 @@ mod tests {
+         assert_eq!(m1, e1);
+     }
+ 
++
++    #[cfg(bitflags_const_fn)]
+     #[test]
+     fn test_const_fn() {
+         const _M1: Flags = Flags::empty();
+@@ -1481,11 +1259,6 @@ mod tests {
+         assert_eq!(hash(&x), hash(&y));
+     }
+ 
+-    #[test]
+-    fn test_default() {
+-        assert_eq!(Flags::empty(), Flags::default());
+-    }
+-
+     #[test]
+     fn test_debug() {
+         assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B");
+@@ -1494,13 +1267,7 @@ mod tests {
+         let extra = unsafe { Flags::from_bits_unchecked(0xb8) };
+         assert_eq!(format!("{:?}", extra), "0xb8");
+         assert_eq!(format!("{:?}", Flags::A | extra), "A | 0xb8");
+-
+-        assert_eq!(
+-            format!("{:?}", Flags::ABC | extra),
+-            "A | B | C | ABC | 0xb8"
+-        );
+-
+-        assert_eq!(format!("{:?}", EmptyFlags::empty()), "(empty)");
++        assert_eq!(format!("{:?}", Flags::ABC | extra), "A | B | C | ABC | 0xb8");
+     }
+ 
+     #[test]
+@@ -1544,7 +1311,8 @@ mod tests {
+             pub struct PublicFlags: i8 {
+                 const X = 0;
+             }
+-
++        }
++        bitflags! {
+             struct PrivateFlags: i8 {
+                 const Y = 0;
+             }
+@@ -1659,71 +1427,4 @@ mod tests {
+         assert_eq!(format!("{:?}", Flags::empty()), "NONE");
+         assert_eq!(format!("{:?}", Flags::SOME), "SOME");
+     }
+-
+-    #[test]
+-    fn test_empty_bitflags() {
+-        bitflags! {}
+-    }
+-
+-    #[test]
+-    fn test_u128_bitflags() {
+-        bitflags! {
+-            struct Flags128: u128 {
+-                const A = 0x0000_0000_0000_0000_0000_0000_0000_0001;
+-                const B = 0x0000_0000_0000_1000_0000_0000_0000_0000;
+-                const C = 0x8000_0000_0000_0000_0000_0000_0000_0000;
+-                const ABC = Self::A.bits | Self::B.bits | Self::C.bits;
+-            }
+-        }
+-
+-        assert_eq!(Flags128::ABC, Flags128::A | Flags128::B | Flags128::C);
+-        assert_eq!(Flags128::A.bits, 0x0000_0000_0000_0000_0000_0000_0000_0001);
+-        assert_eq!(Flags128::B.bits, 0x0000_0000_0000_1000_0000_0000_0000_0000);
+-        assert_eq!(Flags128::C.bits, 0x8000_0000_0000_0000_0000_0000_0000_0000);
+-        assert_eq!(
+-            Flags128::ABC.bits,
+-            0x8000_0000_0000_1000_0000_0000_0000_0001
+-        );
+-        assert_eq!(format!("{:?}", Flags128::A), "A");
+-        assert_eq!(format!("{:?}", Flags128::B), "B");
+-        assert_eq!(format!("{:?}", Flags128::C), "C");
+-        assert_eq!(format!("{:?}", Flags128::ABC), "A | B | C | ABC");
+-    }
+-
+-    #[test]
+-    fn test_serde_bitflags_serialize() {
+-        let flags = SerdeFlags::A | SerdeFlags::B;
+-
+-        let serialized = serde_json::to_string(&flags).unwrap();
+-
+-        assert_eq!(serialized, r#"{"bits":3}"#);
+-    }
+-
+-    #[test]
+-    fn test_serde_bitflags_deserialize() {
+-        let deserialized: SerdeFlags = serde_json::from_str(r#"{"bits":12}"#).unwrap();
+-
+-        let expected = SerdeFlags::C | SerdeFlags::D;
+-
+-        assert_eq!(deserialized.bits, expected.bits);
+-    }
+-
+-    #[test]
+-    fn test_serde_bitflags_roundtrip() {
+-        let flags = SerdeFlags::A | SerdeFlags::B;
+-
+-        let deserialized: SerdeFlags = serde_json::from_str(&serde_json::to_string(&flags).unwrap()).unwrap();
+-
+-        assert_eq!(deserialized.bits, flags.bits);
+-    }
+-
+-    bitflags! {
+-        #[derive(serde::Serialize, serde::Deserialize)]
+-        struct SerdeFlags: u32 {
+-            const A = 1;
+-            const B = 2;
+-            const C = 4;
+-            const D = 8;
+-        }
+-    }
+ }
+diff --git a/third_party/rust/bitflags/tests/basic.rs b/third_party/rust/bitflags/tests/basic.rs
+deleted file mode 100644
+index 73a52bec50b60..0000000000000
+--- a/third_party/rust/bitflags/tests/basic.rs
++++ /dev/null
+@@ -1,20 +0,0 @@
+-#![no_std]
+-
+-use bitflags::bitflags;
+-
+-bitflags! {
+-    /// baz
+-    struct Flags: u32 {
+-        const A = 0b00000001;
+-        #[doc = "bar"]
+-        const B = 0b00000010;
+-        const C = 0b00000100;
+-        #[doc = "foo"]
+-        const ABC = Flags::A.bits | Flags::B.bits | Flags::C.bits;
+-    }
+-}
+-
+-#[test]
+-fn basic() {
+-    assert_eq!(Flags::ABC, Flags::A | Flags::B | Flags::C);
+-}
+diff --git a/third_party/rust/bitflags/tests/compile-fail/impls/copy.rs b/third_party/rust/bitflags/tests/compile-fail/impls/copy.rs
+deleted file mode 100644
+index 38f4822f5a5f2..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-fail/impls/copy.rs
++++ /dev/null
+@@ -1,10 +0,0 @@
+-use bitflags::bitflags;
+-
+-bitflags! {
+-    #[derive(Clone, Copy)]
+-    struct Flags: u32 {
+-        const A = 0b00000001;
+-    }
+-}
+-
+-fn main() {}
+diff --git a/third_party/rust/bitflags/tests/compile-fail/impls/copy.stderr.beta b/third_party/rust/bitflags/tests/compile-fail/impls/copy.stderr.beta
+deleted file mode 100644
+index 0c13aa5024197..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-fail/impls/copy.stderr.beta
++++ /dev/null
+@@ -1,27 +0,0 @@
+-error[E0119]: conflicting implementations of trait `std::clone::Clone` for type `Flags`
+- --> $DIR/copy.rs:3:1
+-  |
+-3 | / bitflags! {
+-4 | |     #[derive(Clone, Copy)]
+-  | |              ----- first implementation here
+-5 | |     struct Flags: u32 {
+-6 | |         const A = 0b00000001;
+-7 | |     }
+-8 | | }
+-  | |_^ conflicting implementation for `Flags`
+-  |
+-  = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+-
+-error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `Flags`
+- --> $DIR/copy.rs:3:1
+-  |
+-3 | / bitflags! {
+-4 | |     #[derive(Clone, Copy)]
+-  | |                     ---- first implementation here
+-5 | |     struct Flags: u32 {
+-6 | |         const A = 0b00000001;
+-7 | |     }
+-8 | | }
+-  | |_^ conflicting implementation for `Flags`
+-  |
+-  = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
+diff --git a/third_party/rust/bitflags/tests/compile-fail/impls/eq.rs b/third_party/rust/bitflags/tests/compile-fail/impls/eq.rs
+deleted file mode 100644
+index 4abbd630c6e12..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-fail/impls/eq.rs
++++ /dev/null
+@@ -1,10 +0,0 @@
+-use bitflags::bitflags;
+-
+-bitflags! {
+-    #[derive(PartialEq, Eq)]
+-    struct Flags: u32 {
+-        const A = 0b00000001;
+-    }
+-}
+-
+-fn main() {}
+diff --git a/third_party/rust/bitflags/tests/compile-fail/impls/eq.stderr.beta b/third_party/rust/bitflags/tests/compile-fail/impls/eq.stderr.beta
+deleted file mode 100644
+index 8a1a3b410a0e0..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-fail/impls/eq.stderr.beta
++++ /dev/null
+@@ -1,55 +0,0 @@
+-error[E0119]: conflicting implementations of trait `std::cmp::PartialEq` for type `Flags`
+- --> $DIR/eq.rs:3:1
+-  |
+-3 | / bitflags! {
+-4 | |     #[derive(PartialEq, Eq)]
+-  | |              --------- first implementation here
+-5 | |     struct Flags: u32 {
+-6 | |         const A = 0b00000001;
+-7 | |     }
+-8 | | }
+-  | |_^ conflicting implementation for `Flags`
+-  |
+-  = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+-
+-error[E0119]: conflicting implementations of trait `std::cmp::Eq` for type `Flags`
+- --> $DIR/eq.rs:3:1
+-  |
+-3 | / bitflags! {
+-4 | |     #[derive(PartialEq, Eq)]
+-  | |                         -- first implementation here
+-5 | |     struct Flags: u32 {
+-6 | |         const A = 0b00000001;
+-7 | |     }
+-8 | | }
+-  | |_^ conflicting implementation for `Flags`
+-  |
+-  = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+-
+-error[E0119]: conflicting implementations of trait `std::marker::StructuralPartialEq` for type `Flags`
+- --> $DIR/eq.rs:3:1
+-  |
+-3 | / bitflags! {
+-4 | |     #[derive(PartialEq, Eq)]
+-  | |              --------- first implementation here
+-5 | |     struct Flags: u32 {
+-6 | |         const A = 0b00000001;
+-7 | |     }
+-8 | | }
+-  | |_^ conflicting implementation for `Flags`
+-  |
+-  = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
+-
+-error[E0119]: conflicting implementations of trait `std::marker::StructuralEq` for type `Flags`
+- --> $DIR/eq.rs:3:1
+-  |
+-3 | / bitflags! {
+-4 | |     #[derive(PartialEq, Eq)]
+-  | |                         -- first implementation here
+-5 | |     struct Flags: u32 {
+-6 | |         const A = 0b00000001;
+-7 | |     }
+-8 | | }
+-  | |_^ conflicting implementation for `Flags`
+-  |
+-  = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+diff --git a/third_party/rust/bitflags/tests/compile-fail/non_integer_base/all_defined.rs b/third_party/rust/bitflags/tests/compile-fail/non_integer_base/all_defined.rs
+deleted file mode 100644
+index c2856b10830d3..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-fail/non_integer_base/all_defined.rs
++++ /dev/null
+@@ -1,123 +0,0 @@
+-use std::{
+-    fmt::{
+-        self,
+-        Debug,
+-        Display,
+-        LowerHex,
+-        UpperHex,
+-        Octal,
+-        Binary,
+-    },
+-    ops::{
+-        BitAnd,
+-        BitOr,
+-        BitXor,
+-        BitAndAssign,
+-        BitOrAssign,
+-        BitXorAssign,
+-        Not,
+-    },
+-};
+-
+-use bitflags::bitflags;
+-
+-// Ideally we'd actually want this to work, but currently need something like `num`'s `Zero`
+-// With some design work it could be made possible
+-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+-struct MyInt(u8);
+-
+-impl BitAnd for MyInt {
+-    type Output = Self;
+-
+-    fn bitand(self, other: Self) -> Self {
+-        MyInt(self.0 & other.0)
+-    }
+-}
+-
+-impl BitOr for MyInt {
+-    type Output = Self;
+-
+-    fn bitor(self, other: Self) -> Self {
+-        MyInt(self.0 | other.0)
+-    }
+-}
+-
+-impl BitXor for MyInt {
+-    type Output = Self;
+-
+-    fn bitxor(self, other: Self) -> Self {
+-        MyInt(self.0 ^ other.0)
+-    }
+-}
+-
+-impl BitAndAssign for MyInt {
+-    fn bitand_assign(&mut self, other: Self) {
+-        self.0 &= other.0
+-    }
+-}
+-
+-impl BitOrAssign for MyInt {
+-    fn bitor_assign(&mut self, other: Self) {
+-        self.0 |= other.0
+-    }
+-}
+-
+-impl BitXorAssign for MyInt {
+-    fn bitxor_assign(&mut self, other: Self) {
+-        self.0 ^= other.0
+-    }
+-}
+-
+-impl Debug for MyInt {
+-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+-        Debug::fmt(&self.0, f)
+-    }
+-}
+-
+-impl Display for MyInt {
+-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+-        Display::fmt(&self.0, f)
+-    }
+-}
+-
+-impl LowerHex for MyInt {
+-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+-        LowerHex::fmt(&self.0, f)
+-    }
+-}
+-
+-impl UpperHex for MyInt {
+-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+-        UpperHex::fmt(&self.0, f)
+-    }
+-}
+-
+-impl Octal for MyInt {
+-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+-        Octal::fmt(&self.0, f)
+-    }
+-}
+-
+-impl Binary for MyInt {
+-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+-        Binary::fmt(&self.0, f)
+-    }
+-}
+-
+-impl Not for MyInt {
+-    type Output = MyInt;
+-
+-    fn not(self) -> Self {
+-        MyInt(!self.0)
+-    }
+-}
+-
+-bitflags! {
+-    struct Flags128: MyInt {
+-        const A = MyInt(0b0000_0001u8);
+-        const B = MyInt(0b0000_0010u8);
+-        const C = MyInt(0b0000_0100u8);
+-    }
+-}
+-
+-fn main() {}
+diff --git a/third_party/rust/bitflags/tests/compile-fail/non_integer_base/all_defined.stderr.beta b/third_party/rust/bitflags/tests/compile-fail/non_integer_base/all_defined.stderr.beta
+deleted file mode 100644
+index 1f0fb5cf7ad0b..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-fail/non_integer_base/all_defined.stderr.beta
++++ /dev/null
+@@ -1,27 +0,0 @@
+-error[E0308]: mismatched types
+-   --> $DIR/all_defined.rs:115:1
+-    |
+-115 | / bitflags! {
+-116 | |     struct Flags128: MyInt {
+-117 | |         const A = MyInt(0b0000_0001u8);
+-118 | |         const B = MyInt(0b0000_0010u8);
+-119 | |         const C = MyInt(0b0000_0100u8);
+-120 | |     }
+-121 | | }
+-    | |_^ expected struct `MyInt`, found integer
+-    |
+-    = note: this error originates in the macro `__impl_all_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info)
+-
+-error[E0308]: mismatched types
+-   --> $DIR/all_defined.rs:115:1
+-    |
+-115 | / bitflags! {
+-116 | |     struct Flags128: MyInt {
+-117 | |         const A = MyInt(0b0000_0001u8);
+-118 | |         const B = MyInt(0b0000_0010u8);
+-119 | |         const C = MyInt(0b0000_0100u8);
+-120 | |     }
+-121 | | }
+-    | |_^ expected struct `MyInt`, found integer
+-    |
+-    = note: this error originates in the macro `__impl_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info)
+diff --git a/third_party/rust/bitflags/tests/compile-fail/non_integer_base/all_missing.rs b/third_party/rust/bitflags/tests/compile-fail/non_integer_base/all_missing.rs
+deleted file mode 100644
+index fff6b2cc13062..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-fail/non_integer_base/all_missing.rs
++++ /dev/null
+@@ -1,13 +0,0 @@
+-use bitflags::bitflags;
+-
+-struct MyInt(u8);
+-
+-bitflags! {
+-    struct Flags128: MyInt {
+-        const A = MyInt(0b0000_0001);
+-        const B = MyInt(0b0000_0010);
+-        const C = MyInt(0b0000_0100);
+-    }
+-}
+-
+-fn main() {}
+diff --git a/third_party/rust/bitflags/tests/compile-fail/non_integer_base/all_missing.stderr.beta b/third_party/rust/bitflags/tests/compile-fail/non_integer_base/all_missing.stderr.beta
+deleted file mode 100644
+index ee95f8365e33e..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-fail/non_integer_base/all_missing.stderr.beta
++++ /dev/null
+@@ -1,13 +0,0 @@
+-error[E0204]: the trait `Copy` may not be implemented for this type
+-  --> $DIR/all_missing.rs:5:1
+-   |
+-5  | / bitflags! {
+-6  | |     struct Flags128: MyInt {
+-7  | |         const A = MyInt(0b0000_0001);
+-8  | |         const B = MyInt(0b0000_0010);
+-9  | |         const C = MyInt(0b0000_0100);
+-10 | |     }
+-11 | | }
+-   | |_^ this field does not implement `Copy`
+-   |
+-   = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
+diff --git a/third_party/rust/bitflags/tests/compile-fail/visibility/private_field.rs b/third_party/rust/bitflags/tests/compile-fail/visibility/private_field.rs
+deleted file mode 100644
+index a6a3912aea30a..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-fail/visibility/private_field.rs
++++ /dev/null
+@@ -1,13 +0,0 @@
+-mod example {
+-    use bitflags::bitflags;
+-
+-    bitflags! {
+-        pub struct Flags1: u32 {
+-            const FLAG_A = 0b00000001;
+-        }
+-    }
+-}
+-
+-fn main() {
+-    let flag1 = example::Flags1::FLAG_A.bits;
+-}
+diff --git a/third_party/rust/bitflags/tests/compile-fail/visibility/private_field.stderr.beta b/third_party/rust/bitflags/tests/compile-fail/visibility/private_field.stderr.beta
+deleted file mode 100644
+index 58a04660166a8..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-fail/visibility/private_field.stderr.beta
++++ /dev/null
+@@ -1,10 +0,0 @@
+-error[E0616]: field `bits` of struct `Flags1` is private
+-  --> $DIR/private_field.rs:12:41
+-   |
+-12 |     let flag1 = example::Flags1::FLAG_A.bits;
+-   |                                         ^^^^ private field
+-   |
+-help: a method `bits` also exists, call it with parentheses
+-   |
+-12 |     let flag1 = example::Flags1::FLAG_A.bits();
+-   |                                             ^^
+diff --git a/third_party/rust/bitflags/tests/compile-fail/visibility/private_flags.rs b/third_party/rust/bitflags/tests/compile-fail/visibility/private_flags.rs
+deleted file mode 100644
+index 85a5b1863dd43..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-fail/visibility/private_flags.rs
++++ /dev/null
+@@ -1,18 +0,0 @@
+-mod example {
+-    use bitflags::bitflags;
+-
+-    bitflags! {
+-        pub struct Flags1: u32 {
+-            const FLAG_A = 0b00000001;
+-        }
+-
+-        struct Flags2: u32 {
+-            const FLAG_B = 0b00000010;
+-        }
+-    }
+-}
+-
+-fn main() {
+-    let flag1 = example::Flags1::FLAG_A;
+-    let flag2 = example::Flags2::FLAG_B;
+-}
+diff --git a/third_party/rust/bitflags/tests/compile-fail/visibility/private_flags.stderr.beta b/third_party/rust/bitflags/tests/compile-fail/visibility/private_flags.stderr.beta
+deleted file mode 100644
+index d23f83209ba90..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-fail/visibility/private_flags.stderr.beta
++++ /dev/null
+@@ -1,18 +0,0 @@
+-error[E0603]: struct `Flags2` is private
+-  --> $DIR/private_flags.rs:17:26
+-   |
+-17 |     let flag2 = example::Flags2::FLAG_B;
+-   |                          ^^^^^^ private struct
+-   |
+-note: the struct `Flags2` is defined here
+-  --> $DIR/private_flags.rs:4:5
+-   |
+-4  | /     bitflags! {
+-5  | |         pub struct Flags1: u32 {
+-6  | |             const FLAG_A = 0b00000001;
+-7  | |         }
+-...  |
+-11 | |         }
+-12 | |     }
+-   | |_____^
+-   = note: this error originates in the macro `bitflags` (in Nightly builds, run with -Z macro-backtrace for more info)
+diff --git a/third_party/rust/bitflags/tests/compile-fail/visibility/pub_const.rs b/third_party/rust/bitflags/tests/compile-fail/visibility/pub_const.rs
+deleted file mode 100644
+index b90f0ce92d1e6..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-fail/visibility/pub_const.rs
++++ /dev/null
+@@ -1,9 +0,0 @@
+-use bitflags::bitflags;
+-
+-bitflags! {
+-    pub struct Flags1: u32 {
+-        pub const FLAG_A = 0b00000001;
+-    }
+-}
+-
+-fn main() {}
+diff --git a/third_party/rust/bitflags/tests/compile-fail/visibility/pub_const.stderr.beta b/third_party/rust/bitflags/tests/compile-fail/visibility/pub_const.stderr.beta
+deleted file mode 100644
+index b01122c7ad879..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-fail/visibility/pub_const.stderr.beta
++++ /dev/null
+@@ -1,5 +0,0 @@
+-error: no rules expected the token `pub`
+- --> $DIR/pub_const.rs:5:9
+-  |
+-5 |         pub const FLAG_A = 0b00000001;
+-  |         ^^^ no rules expected this token in macro call
+diff --git a/third_party/rust/bitflags/tests/compile-pass/impls/convert.rs b/third_party/rust/bitflags/tests/compile-pass/impls/convert.rs
+deleted file mode 100644
+index 1f02982a8fa24..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-pass/impls/convert.rs
++++ /dev/null
+@@ -1,17 +0,0 @@
+-use bitflags::bitflags;
+-
+-bitflags! {
+-    struct Flags: u32 {
+-        const A = 0b00000001;
+-    }
+-}
+-
+-impl From<u32> for Flags {
+-    fn from(v: u32) -> Flags {
+-        Flags::from_bits_truncate(v)
+-    }
+-}
+-
+-fn main() {
+-
+-}
+diff --git a/third_party/rust/bitflags/tests/compile-pass/impls/default.rs b/third_party/rust/bitflags/tests/compile-pass/impls/default.rs
+deleted file mode 100644
+index a97b6536f2b58..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-pass/impls/default.rs
++++ /dev/null
+@@ -1,10 +0,0 @@
+-use bitflags::bitflags;
+-
+-bitflags! {
+-    #[derive(Default)]
+-    struct Flags: u32 {
+-        const A = 0b00000001;
+-    }
+-}
+-
+-fn main() {}
+diff --git a/third_party/rust/bitflags/tests/compile-pass/impls/inherent_methods.rs b/third_party/rust/bitflags/tests/compile-pass/impls/inherent_methods.rs
+deleted file mode 100644
+index 3052c460ec33a..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-pass/impls/inherent_methods.rs
++++ /dev/null
+@@ -1,15 +0,0 @@
+-use bitflags::bitflags;
+-
+-bitflags! {
+-    struct Flags: u32 {
+-        const A = 0b00000001;
+-    }
+-}
+-
+-impl Flags {
+-    pub fn new() -> Flags {
+-        Flags::A
+-    }
+-}
+-
+-fn main() {}
+diff --git a/third_party/rust/bitflags/tests/compile-pass/redefinition/core.rs b/third_party/rust/bitflags/tests/compile-pass/redefinition/core.rs
+deleted file mode 100644
+index 47549215948d1..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-pass/redefinition/core.rs
++++ /dev/null
+@@ -1,14 +0,0 @@
+-use bitflags::bitflags;
+-
+-// Checks for possible errors caused by overriding names used by `bitflags!` internally.
+-
+-mod core {}
+-mod _core {}
+-
+-bitflags! {
+-    struct Test: u8 {
+-        const A = 1;
+-    }
+-}
+-
+-fn main() {}
+diff --git a/third_party/rust/bitflags/tests/compile-pass/redefinition/stringify.rs b/third_party/rust/bitflags/tests/compile-pass/redefinition/stringify.rs
+deleted file mode 100644
+index b04f2f6a49332..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-pass/redefinition/stringify.rs
++++ /dev/null
+@@ -1,19 +0,0 @@
+-use bitflags::bitflags;
+-
+-// Checks for possible errors caused by overriding names used by `bitflags!` internally.
+-
+-#[allow(unused_macros)]
+-macro_rules! stringify {
+-    ($($t:tt)*) => { "..." };
+-}
+-
+-bitflags! {
+-    struct Test: u8 {
+-        const A = 1;
+-    }
+-}
+-
+-fn main() {
+-    // Just make sure we don't call the redefined `stringify` macro
+-    assert_eq!(format!("{:?}", Test::A), "A");
+-}
+diff --git a/third_party/rust/bitflags/tests/compile-pass/repr/c.rs b/third_party/rust/bitflags/tests/compile-pass/repr/c.rs
+deleted file mode 100644
+index 6feba36ed82c1..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-pass/repr/c.rs
++++ /dev/null
+@@ -1,10 +0,0 @@
+-use bitflags::bitflags;
+-
+-bitflags! {
+-    #[repr(C)]
+-    struct Flags: u32 {
+-        const A = 0b00000001;
+-    }
+-}
+-
+-fn main() {}
+diff --git a/third_party/rust/bitflags/tests/compile-pass/repr/transparent.rs b/third_party/rust/bitflags/tests/compile-pass/repr/transparent.rs
+deleted file mode 100644
+index e38db4dd11b99..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-pass/repr/transparent.rs
++++ /dev/null
+@@ -1,10 +0,0 @@
+-use bitflags::bitflags;
+-
+-bitflags! {
+-    #[repr(transparent)]
+-    struct Flags: u32 {
+-        const A = 0b00000001;
+-    }
+-}
+-
+-fn main() {}
+diff --git a/third_party/rust/bitflags/tests/compile-pass/visibility/bits_field.rs b/third_party/rust/bitflags/tests/compile-pass/visibility/bits_field.rs
+deleted file mode 100644
+index 33a7967e629ef..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-pass/visibility/bits_field.rs
++++ /dev/null
+@@ -1,11 +0,0 @@
+-use bitflags::bitflags;
+-
+-bitflags! {
+-    pub struct Flags1: u32 {
+-        const FLAG_A = 0b00000001;
+-    }
+-}
+-
+-fn main() {
+-    assert_eq!(0b00000001, Flags1::FLAG_A.bits);
+-}
+diff --git a/third_party/rust/bitflags/tests/compile-pass/visibility/pub_in.rs b/third_party/rust/bitflags/tests/compile-pass/visibility/pub_in.rs
+deleted file mode 100644
+index c11050e3baf0c..0000000000000
+--- a/third_party/rust/bitflags/tests/compile-pass/visibility/pub_in.rs
++++ /dev/null
+@@ -1,19 +0,0 @@
+-mod a {
+-    mod b {
+-        use bitflags::bitflags;
+-
+-        bitflags! {
+-            pub(in crate::a) struct Flags: u32 {
+-                const FLAG_A = 0b00000001;
+-            }
+-        }
+-    }
+-
+-    pub fn flags() -> u32 {
+-        b::Flags::FLAG_A.bits()
+-    }
+-}
+-
+-fn main() {
+-    assert_eq!(0b00000001, a::flags());
+-}
+diff --git a/third_party/rust/bitflags/tests/compile.rs b/third_party/rust/bitflags/tests/compile.rs
+deleted file mode 100644
+index ed02d01e9ca1b..0000000000000
+--- a/third_party/rust/bitflags/tests/compile.rs
++++ /dev/null
+@@ -1,63 +0,0 @@
+-use std::{
+-    fs,
+-    ffi::OsStr,
+-    io,
+-    path::Path,
+-};
+-
+-use walkdir::WalkDir;
+-
+-#[test]
+-fn fail() {
+-    prepare_stderr_files("tests/compile-fail").unwrap();
+-
+-    let t = trybuild::TestCases::new();
+-    t.compile_fail("tests/compile-fail/**/*.rs");
+-}
+-
+-#[test]
+-fn pass() {
+-    let t = trybuild::TestCases::new();
+-    t.pass("tests/compile-pass/**/*.rs");
+-}
+-
+-// Compiler messages may change between versions
+-// We don't want to have to track these too closely for `bitflags`, but
+-// having some message to check makes sure user-facing errors are sensical.
+-// 
+-// The approach we use is to run the test on all compilers, but only check stderr
+-// output on beta (which is the next stable release). We do this by default ignoring
+-// any `.stderr` files in the `compile-fail` directory, and copying `.stderr.beta` files
+-// when we happen to be running on a beta compiler.
+-fn prepare_stderr_files(path: impl AsRef<Path>) -> io::Result<()> {
+-    for entry in WalkDir::new(path) {
+-        let entry = entry?;
+-
+-        if entry.path().extension().and_then(OsStr::to_str) == Some("beta") {
+-            let renamed = entry.path().with_extension("");
+-
+-            // Unconditionally remove a corresponding `.stderr` file for a `.stderr.beta`
+-            // file if it exists. On `beta` compilers, we'll recreate it. On other compilers,
+-            // we don't want to end up checking it anyways.
+-            if renamed.exists() {
+-                fs::remove_file(&renamed)?;
+-            }
+-
+-            rename_beta_stderr(entry.path(), renamed)?;
+-        }
+-    }
+-
+-    Ok(())
+-}
+-
+-#[rustversion::beta]
+-fn rename_beta_stderr(from: impl AsRef<Path>, to: impl AsRef<Path>) -> io::Result<()> {
+-    fs::copy(from, to)?;
+-
+-    Ok(())
+-}
+-
+-#[rustversion::not(beta)]
+-fn rename_beta_stderr(_: impl AsRef<Path>, _: impl AsRef<Path>) -> io::Result<()> {
+-    Ok(())
+-}
+diff --git a/third_party/rust/midir/.cargo-checksum.json b/third_party/rust/midir/.cargo-checksum.json
+index 390b25b1e0118..34b17c2c5c548 100644
+--- a/third_party/rust/midir/.cargo-checksum.json
++++ b/third_party/rust/midir/.cargo-checksum.json
+@@ -1 +1 @@
+-{"files":{"CHANGELOG.md":"10db6f8dbb1c5566e75f2eeda6b2ee8bb44fe4a76f57e0bfb98c62f7f8c04f89","Cargo.toml":"41aa086ea813af75458515ff515917bb48d20eaef42a74352ea12ff8d5d16bce","LICENSE":"6fe6f623b1fa80e90679aee2f917d8978a184988ebb995ebc254cc9633903cac","README.md":"4131b953217e77a4463fde307ba3262b4df11732c1ff209668df12dff3c73ffc","azure-pipelines-template.yml":"c787791a94e654226a299aaa875fcc48f6eedf4dae631855cb5a7067891dbe3a","azure-pipelines.yml":"1b4fab0afacc66732a385cb6e5b213c170fc9717219a03ccda9c5db78cd461dd","examples/test_forward.rs":"6cb060aba7e8c39eaf53ea95a72d4c7939ffb4bebc82c291135fdc35495078ce","examples/test_list_ports.rs":"41ba21ab1e56d76206abc8b291d27050cb1a788372f00f6761c78f03fb5981ff","examples/test_play.rs":"22630e46af9628d8193ad8e19ff095ad02542b7ab697be4e513da78210ad5c0c","examples/test_read_input.rs":"4901f18435c3f8021750ccd4687abe92194ab38f1e7721896a6a31f6650d524c","examples/test_reuse.rs":"fdb3b430aec42c7c648fbecf22e6c726ef8a20638936a1a70fb373dff94c0632","examples/
 test_sysex.rs":"ea06427a644c3639f1c49271be5d16c9d3890d3741eb6ebf2ff64d2f7fd36e96","src/backend/alsa/mod.rs":"6bc784435247c3302bf12c3f558b6027abfbec997a280baa113c7344e5b0479f","src/backend/coremidi/mod.rs":"f827cbc5db7086ea58c5927213a2c3e0246244d5939c2ba0ff787caae7089511","src/backend/jack/mod.rs":"8f2eace3e9046ec6de8c7fc37d3502d2b971a73fe2a96e5c2a423d51445f1505","src/backend/jack/wrappers.rs":"f18718f234e41c91bb5463546fbbe61be64e9581a4fae6ef2de20cafae487298","src/backend/mod.rs":"1a8106889ecd053af27b3a72515bfb286da1b08bb90909fa6d4e7b816b50c447","src/backend/webmidi/mod.rs":"4af5b288833ee99f047a638b368eca293f89356f1e82147c9a9c1633d950955d","src/backend/winmm/handler.rs":"45b36067fd280a38943f385d3d7f6885d7448153f53e9c8f66b58b484535ad1c","src/backend/winmm/mod.rs":"94d8c57fd2d327993d01ef06d8c68190c528fe52dd39e6b97c88d9f1f0afa753","src/backend/winrt/mod.rs":"ca7ac4ac310e7f6a6c28dd6374bfe97b38ed8656c7ca343494264cce45f93ae6","src/common.rs":"2cab2e987428522ca601544b516b64b858859730fbd1be0
 e53c828e82025319d","src/errors.rs":"495ba80f9dcfeefd343b460b74549b12cb1825c3e1b315848f859d0b4d66ddbe","src/lib.rs":"ecde030ca02a90a99577cd71446857a2c00aee8ff1bc7890c54a5d0d22d2be2c","src/os/mod.rs":"507dfa95e57805c489a883dcf9efddcb718d5178267f296294f72b3c397c12c7","src/os/unix.rs":"a1977659d270fcf31111d4446b949d2760d76e2077639e6008d634800861b77b","tests/virtual.rs":"b47501eeb313f3e255d2d1888c333ff994d958865272929fe7bf116be45b6805"},"package":null}
+\ No newline at end of file
++{"files":{"CHANGELOG.md":"10db6f8dbb1c5566e75f2eeda6b2ee8bb44fe4a76f57e0bfb98c62f7f8c04f89","Cargo.toml":"792c11a1ab6ce0443cb040994b02f1e80e07d19e6bf59f683a7fb227539bc028","LICENSE":"6fe6f623b1fa80e90679aee2f917d8978a184988ebb995ebc254cc9633903cac","README.md":"4131b953217e77a4463fde307ba3262b4df11732c1ff209668df12dff3c73ffc","azure-pipelines-template.yml":"c787791a94e654226a299aaa875fcc48f6eedf4dae631855cb5a7067891dbe3a","azure-pipelines.yml":"1b4fab0afacc66732a385cb6e5b213c170fc9717219a03ccda9c5db78cd461dd","examples/test_forward.rs":"6cb060aba7e8c39eaf53ea95a72d4c7939ffb4bebc82c291135fdc35495078ce","examples/test_list_ports.rs":"41ba21ab1e56d76206abc8b291d27050cb1a788372f00f6761c78f03fb5981ff","examples/test_play.rs":"22630e46af9628d8193ad8e19ff095ad02542b7ab697be4e513da78210ad5c0c","examples/test_read_input.rs":"4901f18435c3f8021750ccd4687abe92194ab38f1e7721896a6a31f6650d524c","examples/test_reuse.rs":"fdb3b430aec42c7c648fbecf22e6c726ef8a20638936a1a70fb373dff94c0632","examples/
 test_sysex.rs":"ea06427a644c3639f1c49271be5d16c9d3890d3741eb6ebf2ff64d2f7fd36e96","src/backend/alsa/mod.rs":"6bc784435247c3302bf12c3f558b6027abfbec997a280baa113c7344e5b0479f","src/backend/coremidi/mod.rs":"f827cbc5db7086ea58c5927213a2c3e0246244d5939c2ba0ff787caae7089511","src/backend/jack/mod.rs":"8f2eace3e9046ec6de8c7fc37d3502d2b971a73fe2a96e5c2a423d51445f1505","src/backend/jack/wrappers.rs":"f18718f234e41c91bb5463546fbbe61be64e9581a4fae6ef2de20cafae487298","src/backend/mod.rs":"1a8106889ecd053af27b3a72515bfb286da1b08bb90909fa6d4e7b816b50c447","src/backend/webmidi/mod.rs":"4af5b288833ee99f047a638b368eca293f89356f1e82147c9a9c1633d950955d","src/backend/winmm/handler.rs":"45b36067fd280a38943f385d3d7f6885d7448153f53e9c8f66b58b484535ad1c","src/backend/winmm/mod.rs":"94d8c57fd2d327993d01ef06d8c68190c528fe52dd39e6b97c88d9f1f0afa753","src/backend/winrt/mod.rs":"ca7ac4ac310e7f6a6c28dd6374bfe97b38ed8656c7ca343494264cce45f93ae6","src/common.rs":"2cab2e987428522ca601544b516b64b858859730fbd1be0
 e53c828e82025319d","src/errors.rs":"495ba80f9dcfeefd343b460b74549b12cb1825c3e1b315848f859d0b4d66ddbe","src/lib.rs":"ecde030ca02a90a99577cd71446857a2c00aee8ff1bc7890c54a5d0d22d2be2c","src/os/mod.rs":"507dfa95e57805c489a883dcf9efddcb718d5178267f296294f72b3c397c12c7","src/os/unix.rs":"a1977659d270fcf31111d4446b949d2760d76e2077639e6008d634800861b77b","tests/virtual.rs":"b47501eeb313f3e255d2d1888c333ff994d958865272929fe7bf116be45b6805"},"package":null}
+\ No newline at end of file
+diff --git a/third_party/rust/midir/Cargo.toml b/third_party/rust/midir/Cargo.toml
+index 49089e0ffe86e..ac48aab304db9 100644
+--- a/third_party/rust/midir/Cargo.toml
++++ b/third_party/rust/midir/Cargo.toml
+@@ -28,8 +28,8 @@ libc = { version = "0.2.21", optional = true }
+ winrt = { version = "0.7.0", optional = true}
+ 
+ [target.'cfg(target_os = "linux")'.dependencies]
+-alsa = "0.4.3"
+-nix = "0.15"
++alsa = "0.5.0"
++nix = "0.20"
+ libc = "0.2.21"
+ 
+ [target.'cfg(target_os = "macos")'.dependencies]
+diff --git a/third_party/rust/nix-0.15.0/.cargo-checksum.json b/third_party/rust/nix-0.15.0/.cargo-checksum.json
+new file mode 100644
+index 0000000000000..e5f2bc789185a
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/.cargo-checksum.json
+@@ -0,0 +1 @@
++{"files":{"CHANGELOG.md":"91af9fd5f2d9cdb9c8bb750e24b625742e95a6c74bcff419f3de70eb26578281","CONTRIBUTING.md":"a9101e3d1487170d691d5f062ff49a433c167582ac8984dd41a744be92652f74","CONVENTIONS.md":"e150ce43c1d188c392c1a3bf7f2e08e3cf84906705c7bef43f319037d29ea385","Cargo.toml":"af0cc0ae7ff4bf6c2e5b35fe062f54fe2d619f70ba67795f4f43a981420b5de0","LICENSE":"66e3ee1fa7f909ad3c612d556f2a0cdabcd809ad6e66f3b0605015ac64841b70","README.md":"80d71b9eaac7bf7f0d307372592ed1467f994291e6fad816a44f3c70e2887d0f","build.rs":"14c9c678c33f5894509da47f77d6a326b14aecb4190ce87a24cce98687ca63b2","src/dir.rs":"21e330cbe6594274335b94d9e9b6059f1fa8e53d2e5b5c697058c52ec6b3c5ff","src/errno.rs":"a009ccf18b45c0a4c9319c65b0dc5bc322d9ad43cfe462ec4661559f44162451","src/errno_dragonfly.c":"a857e47b114acb85fddcb252a610ab5734d225c26b7bedd7c35d7789d46c8526","src/fcntl.rs":"6ae2f7f01dd2568b82a4e57f86e02b1d63eec6c26111c5adb2ca5d78a2a99fe7","src/features.rs":"22ff626ff8287a07dd55bcfc63c9f518c19c56144e15f9b6f9e3bbdcda51c2a8","
 src/ifaddrs.rs":"9a93de176edcca4613e668b8ccc2c3e3b6b711aa2d8d94ccb0ba08694d1ef35f","src/kmod.rs":"4d8a695d3d761f351a39d654303a1bd168e74295b7d142b918737e355b24f34d","src/lib.rs":"fdd8049a79ffb92384c72f0a6b0bab717001ddfa9b01f2b33413c83f424f2ac8","src/macros.rs":"aec27fa0fd98900913fada926c9a4581cd28f2640e3a7b5480707f923c9200f8","src/mount.rs":"cdf5db8409017483132db9d7493b5d6cc96df5560d0fa5ad8f385aff72db10ca","src/mqueue.rs":"82af42b31381af73e7966f845d1ed93957f0b9976bf2da524b178fad15b2b08d","src/net/if_.rs":"f7e02076fcf3cadf3fdf141884c9bd2c468a7047ba60bc490f0057df802b53ce","src/net/mod.rs":"577f70170e53d4a6de1abb70bf8f1031ec3e65c0e63ef5fcf05c907125e7ac17","src/poll.rs":"7305e250066cd1a7318cd239ed3db787937ee98426fe9289cf00fa874d76b6c7","src/pty.rs":"6b965b586579933af47d4efef4c82c391b927037eaa08d8c83fc974ef17fc7c8","src/sched.rs":"f9b214fa60006b5450ffb3589a55ec59c3694bd49597c65c38ac813fcd96c7dd","src/sys/aio.rs":"a1ba629258b3ce1268e5fe8e5b41dce3581f77d415dc5e2455c1f82f26dd3085","src/sys/e
 poll.rs":"f0b539e0645569657f2142db91a38c94ebe1925f44852d64c61c818758dbbf0b","src/sys/event.rs":"ef8bc02a08d9ce7924c87f8f891fa051587b195a36913712fe85237a2fe0685b","src/sys/eventfd.rs":"08008cf3dc64c2216847c02c0dd8d7189cf08edbaafe35ba2c57c053fde09ef4","src/sys/inotify.rs":"687c8417d737939aa93f805d6003afc4f84f50828b1bd9429ef5d00bef0e0955","src/sys/ioctl/bsd.rs":"56ca6ecf5f7cfb566f4f3ba589fcc778f747a517dd45e13780981922e6215344","src/sys/ioctl/linux.rs":"6cfbdff4dbfa1a3782acdedebe89ffa9f000fdfc4ab68cb46f52890ebc1c6f2d","src/sys/ioctl/mod.rs":"20bc3cf1fcbbc7c31e4d507baa4e576a793ea42fb33618d2e7afeda730c4324f","src/sys/memfd.rs":"11cd93c867fdbdbc9588cecb94268691de42b2ef2a38fe33525be7c7f60c85d5","src/sys/mman.rs":"f77d28611a7ff3bf62784a3c4f26d7d79969395b1d9bbc6ff15e734f52dc404f","src/sys/mod.rs":"f39a08c72e37638c7cecfb9c087e0a41e2b69409aa545b0ef7bbd59c0a063ee2","src/sys/pthread.rs":"cfa9ccd6f3b86c0c3fe012773c9c82a7813b298c2f20f8ab629781db627ce56b","src/sys/ptrace/bsd.rs":"8a7eacfc172b55763ae
 32109bf9b252669ba68b72cd5122f7504eb35c0c08345","src/sys/ptrace/linux.rs":"f09b45148004f4b28d8503c397a8d112d31046c98e68335bf4e89425d5b33f07","src/sys/ptrace/mod.rs":"671a6ccac955e75d5998f7e53ffc45ed4c7b6522a0f24a0937d60141f692dd39","src/sys/quota.rs":"7eb8e797466b506f6ed882f18eda92c4639cf43d9384a19bc39cd1bf982989c9","src/sys/reboot.rs":"fde9da27c2928f7026231430fa14fec2058df4e49a0aeda2a237a60524f11241","src/sys/select.rs":"57d6c4403d1bf788bd52ab6f03cfc16a189d31b6bfb338b135cb775fe369121f","src/sys/sendfile.rs":"ea386e83baf9b5b23488aca26635aacdc92f2bfe238e4399a7380bd0331e0ef7","src/sys/signal.rs":"9216cdd609b4dfb9c2e559c411be6b7c722f7ddd8024682c0895a32126b488aa","src/sys/signalfd.rs":"bfcfce619bf199e50f9cc80a3eb778d48474a015cfdafc64a0c3517373a225a9","src/sys/socket/addr.rs":"8b297ce13cd8ad200b3e764888c26ceb582ee505385d1e172440de94ade99644","src/sys/socket/mod.rs":"e0353f04f3d098a8bf5e2aae431645897b96e0889fb76537dc0330159c6f233d","src/sys/socket/sockopt.rs":"c663505d6a7a7ae9d76e03fbc17e5
 3d308ea6b1eae92212812e1d76b2bf2916f","src/sys/stat.rs":"c4807048f86be67026756737cf81f448ec23c2a4745776cb40f40b533a88e0c8","src/sys/statfs.rs":"d2b72069f20aa7782ce5de4ec2d00c76a82a92376c2066bbb270cdac2167719e","src/sys/statvfs.rs":"2d328cf525ba04ab1e1351128624a7df7d0c55ea91fda6c8d620d13710d61606","src/sys/sysinfo.rs":"0c05244655aa9e6dff5138392c5c1ae97630d35bae0e5510d7f51a75c31fd425","src/sys/termios.rs":"a2e99afdfc3526641a2cb82b57bfd0a25a362fb9be5ad37ff9f11acaeb0b9439","src/sys/time.rs":"8a1224b9262026086af698630aedbed21b45d661fbd045fc6c6af41a16a23374","src/sys/uio.rs":"60a974275ff8c485ea183bdd6f7e25894e6f2360a5bfb25442391a825a3b9b8c","src/sys/utsname.rs":"c977a1aec6e051c72b27506395e942abab9cbd9523e6d345ea66dc10875ee87d","src/sys/wait.rs":"30b14a8f518d031805cae6c6ff644116f162d8c8a75fddcfce4479d8d55fd1c0","src/ucontext.rs":"075560ec08a362881534211f8c6b78844886d6b767c2f7067174600e38ed3f63","src/unistd.rs":"82308ec31b6293b55f86fafd04e976a41127fedebb8f158abd1399c7399af947","test/sys/mod.
 rs":"e0821cbc289ad952f17229609c7de4282cca1e44cd13e1a7494a6378ecbc12f8","test/sys/test_aio.rs":"b2544bfb321ca7fbed276ee637c769fb438156d14666cdc1e1d547b3514a44e3","test/sys/test_aio_drop.rs":"30dd1d238269d00381fa50f6d3cb2b13794b7cceb9f6455f3878fcbffa9aa62d","test/sys/test_epoll.rs":"35093d0cb1096a934dfc4f6efc737eadc4bdc2e2134d2a879061374a51b10c97","test/sys/test_inotify.rs":"a4f804bcf414b6635d9863c8534769a609009c451c3476cc839cdc30c439b3b1","test/sys/test_ioctl.rs":"eea690ed386da0a666df5eb23a417421fddb99dc8e39556f63b30969bb6cf779","test/sys/test_lio_listio_resubmit.rs":"203a583313542593148f375b087ae30620222a745680173fa98fc448d1e5ae7f","test/sys/test_pthread.rs":"3890e5ecbf2082e0d05d102cc9cec6e76ede3c15f250d104e3483b1c1c3400b1","test/sys/test_ptrace.rs":"4e8d5dff5fe6bc56e4ae53bdfd10f5e8ea567d8099576d1c690cf7a6b2bc955f","test/sys/test_select.rs":"bdb20211fc6ec1e3f186337eac51e08757acb6901d307d67c71bf9011f0d54bd","test/sys/test_signal.rs":"84ae63c2baa49eebeabe5bbd347b9c5417e14ba97f342719d7
 53dc1c1c768d60","test/sys/test_signalfd.rs":"71b5d6d782283f6db64ca90f7fb06617faec71091d59d2587e41bbc9d8c43d5c","test/sys/test_socket.rs":"09a7ef0322e07b4579893e0307a7c4f81fbbc653d005b827a519c33a33e185ce","test/sys/test_sockopt.rs":"b3d386c8279f86bf9439c772317bafcdba5630fa806c8319e87ddac0ccfa3a03","test/sys/test_sysinfo.rs":"1e1bea9130fe38ccb07cd0ad7334c7be1e45efc33f7656a5973f8cad7126f225","test/sys/test_termios.rs":"fa4be3ade859b527bf33408f85a6f57b127917cf5f2afb662d09f6019d07913a","test/sys/test_uio.rs":"9da234e3bd5003fd200cc37c4a5be147ecda1a7670feb1d505f23d646d3e1c57","test/sys/test_wait.rs":"e6c5147e213daa93892cd828f53214995d2e019ff2372cc48d85ce9b93d26ec9","test/test.rs":"e6307f82a39426a949b8e925a2df4a62e31c0e43081d7a33d23759bdfeeece1f","test/test_dir.rs":"5d137a62f11d1a4993b4bb35dccc38a4c4416b7da374887f2335a9895b4fdee4","test/test_fcntl.rs":"730e64e99dc867ba5af7cc4ca83a4489c8b96b1a52f8937bcc666d673af27002","test/test_kmod/hello_mod/Makefile":"0219f7bce0603f97d997fb377ca071966c903
 33ecc665e78a54dfeb97a9c811b","test/test_kmod/hello_mod/hello.c":"bcac6b19c5bd807e1f3878c15e426acc85785a8ade9840c3bb4d068635c9188c","test/test_kmod/mod.rs":"f4754f028402a8ba788c87686288424cd3784e77c7eb5d96682ef491b1dd5262","test/test_mount.rs":"78ddc657f5098360c764fffa3a7d844503e4b6b65b44bfd42d9aa9045b415cb6","test/test_mq.rs":"5806f8825e91edc79dd0e2bc81d8be3ba094c2de6c0b2ac0268221ae2ad22701","test/test_net.rs":"ec6d580b87292519d514b0236bdd5abdd576fcf4835cfe49ed1ddb47c5f1aea3","test/test_nix_path.rs":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","test/test_poll.rs":"46c71ee988fe1b85561ea0530d099750be8c1b8f95ab6e845c8a9f46f16f060c","test/test_pty.rs":"be04f99904fa47b60400c2bd156a388b73df4b9aec2eebf13df7dcdfc9aacf45","test/test_ptymaster_drop.rs":"5cfbbb79551c205ab510c2d4ef497bf937ceac9151fbe2f2e543d6515e406990","test/test_sendfile.rs":"e0cbabbd34052ccaa03d6555d5631686aa076728f6378ee90f7ecec68f891144","test/test_stat.rs":"1dc420d3119bf4d863a7ae0ba63efa7f1416f6e46e4
 100ea161003fe1c3f66ba","test/test_unistd.rs":"0325c998acca1e826e9e2b3d351d55ab9723a6cb2ca2072245978e7f5a9acee8"},"package":"3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229"}
+\ No newline at end of file
+diff --git a/third_party/rust/nix-0.15.0/CHANGELOG.md b/third_party/rust/nix-0.15.0/CHANGELOG.md
+new file mode 100644
+index 0000000000000..d93a5ce6bbfc9
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/CHANGELOG.md
+@@ -0,0 +1,742 @@
++# Change Log
++
++All notable changes to this project will be documented in this file.
++This project adheres to [Semantic Versioning](http://semver.org/).
++
++## [Unreleased] - ReleaseDate
++### Added
++### Changed
++### Fixed
++### Removed
++
++## [0.15.0] - 10 August 2019
++### Added
++- Added `MSG_WAITALL` to `MsgFlags` in `sys::socket`.
++  ([#1079](https://github.com/nix-rust/nix/pull/1079))
++- Implemented `Clone`, `Copy`, `Debug`, `Eq`, `Hash`, and `PartialEq` for most
++  types that support them. ([#1035](https://github.com/nix-rust/nix/pull/1035))
++- Added `copy_file_range` wrapper
++  ([#1069](https://github.com/nix-rust/nix/pull/1069))
++- Add `mkdirat`.
++  ([#1084](https://github.com/nix-rust/nix/pull/1084))
++- Add `posix_fadvise`.
++  ([#1089](https://github.com/nix-rust/nix/pull/1089))
++- Added `AF_VSOCK` to `AddressFamily`.
++  ([#1091](https://github.com/nix-rust/nix/pull/1091))
++- Add `unlinkat`
++  ([#1058](https://github.com/nix-rust/nix/pull/1058))
++- Add `renameat`.
++  ([#1097](https://github.com/nix-rust/nix/pull/1097))
++
++### Changed
++- Support for `ifaddrs` now present when building for Android.
++  ([#1077](https://github.com/nix-rust/nix/pull/1077))
++- Minimum supported Rust version is now 1.31.0
++  ([#1035](https://github.com/nix-rust/nix/pull/1035))
++  ([#1095](https://github.com/nix-rust/nix/pull/1095))
++- Now functions `statfs()` and `fstatfs()` return result with `Statfs` wrapper
++  ([#928](https://github.com/nix-rust/nix/pull/928))
++
++### Fixed
++- Enabled `sched_yield` for all nix hosts.
++  ([#1090](https://github.com/nix-rust/nix/pull/1090))
++
++### Removed
++
++## [0.14.1] - 2019-06-06
++### Added
++- Macros exported by `nix` may now be imported via `use` on the Rust 2018
++  edition without importing helper macros on Linux targets.
++  ([#1066](https://github.com/nix-rust/nix/pull/1066))
++
++  For example, in Rust 2018, the `ioctl_read_bad!` macro can now be imported
++  without importing the `convert_ioctl_res!` macro.
++
++  ```rust
++  use nix::ioctl_read_bad;
++
++  ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios);
++  ```
++
++### Changed
++- Changed some public types from reexports of libc types like `uint32_t` to the
++  native equivalents like `u32.`
++  ([#1072](https://github.com/nix-rust/nix/pull/1072/commits))
++
++### Fixed
++- Fix the build on Android and Linux/mips with recent versions of libc.
++  ([#1072](https://github.com/nix-rust/nix/pull/1072/commits))
++
++### Removed
++
++## [0.14.0] - 2019-05-21
++### Added
++- Add IP_RECVIF & IP_RECVDSTADDR. Enable IP_PKTINFO and IP6_PKTINFO on netbsd/openbsd.
++  ([#1002](https://github.com/nix-rust/nix/pull/1002))
++- Added `inotify_init1`, `inotify_add_watch` and `inotify_rm_watch` wrappers for
++  Android and Linux. ([#1016](https://github.com/nix-rust/nix/pull/1016))
++- Add `ALG_SET_IV`, `ALG_SET_OP` and `ALG_SET_AEAD_ASSOCLEN` control messages and `AF_ALG`
++  socket types on Linux and Android ([#1031](https://github.com/nix-rust/nix/pull/1031))
++- Add killpg
++  ([#1034](https://github.com/nix-rust/nix/pull/1034))
++- Added ENOTSUP errno support for Linux and Android.
++  ([#969](https://github.com/nix-rust/nix/pull/969))
++- Add several errno constants from OpenBSD 6.2
++  ([#1036](https://github.com/nix-rust/nix/pull/1036))
++- Added `from_std` and `to_std` methods for `sys::socket::IpAddr`
++  ([#1043](https://github.com/nix-rust/nix/pull/1043))
++- Added `nix::unistd:seteuid` and `nix::unistd::setegid` for those platforms that do
++  not support `setresuid` nor `setresgid` respectively.
++  ([#1044](https://github.com/nix-rust/nix/pull/1044))
++- Added a `access` wrapper
++  ([#1045](https://github.com/nix-rust/nix/pull/1045))
++- Add `forkpty`
++  ([#1042](https://github.com/nix-rust/nix/pull/1042))
++- Add `sched_yield`
++  ([#1050](https://github.com/nix-rust/nix/pull/1050))
++
++### Changed
++- `PollFd` event flags renamed to `PollFlags` ([#1024](https://github.com/nix-rust/nix/pull/1024/))
++- `recvmsg` now returns an Iterator over `ControlMessageOwned` objects rather
++  than `ControlMessage` objects.  This is sadly not backwards-compatible.  Fix
++  code like this:
++  ```rust
++  if let ControlMessage::ScmRights(&fds) = cmsg {
++  ```
++
++  By replacing it with code like this:
++  ```rust
++  if let ControlMessageOwned::ScmRights(fds) = cmsg {
++  ```
++  ([#1020](https://github.com/nix-rust/nix/pull/1020))
++- Replaced `CmsgSpace` with the `cmsg_space` macro.
++  ([#1020](https://github.com/nix-rust/nix/pull/1020))
++
++### Fixed
++- Fixed multiple bugs when using `sendmsg` and `recvmsg` with ancillary control messages
++  ([#1020](https://github.com/nix-rust/nix/pull/1020))
++- Macros exported by `nix` may now be imported via `use` on the Rust 2018
++  edition without importing helper macros for BSD targets.
++  ([#1041](https://github.com/nix-rust/nix/pull/1041))
++
++  For example, in Rust 2018, the `ioctl_read_bad!` macro can now be imported
++  without importing the `convert_ioctl_res!` macro.
++
++  ```rust
++  use nix::ioctl_read_bad;
++
++  ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios);
++  ```
++
++### Removed
++- `Daemon`, `NOTE_REAP`, and `NOTE_EXIT_REPARENTED` are now deprecated on OSX
++  and iOS.
++  ([#1033](https://github.com/nix-rust/nix/pull/1033))
++- `PTRACE_GETREGS`, `PTRACE_SETREGS`, `PTRACE_GETFPREGS`, and
++  `PTRACE_SETFPREGS` have been removed from some platforms where they never
++  should've been defined in the first place.
++  ([#1055](https://github.com/nix-rust/nix/pull/1055))
++
++## [0.13.0] - 2019-01-15
++### Added
++- Added PKTINFO(V4) & V6PKTINFO cmsg support - Android/FreeBSD/iOS/Linux/MacOS.
++  ([#990](https://github.com/nix-rust/nix/pull/990))
++- Added support of CString type in `setsockopt`.
++  ([#972](https://github.com/nix-rust/nix/pull/972))
++- Added option `TCP_CONGESTION` in `setsockopt`.
++  ([#972](https://github.com/nix-rust/nix/pull/972))
++- Added `symlinkat` wrapper.
++  ([#997](https://github.com/nix-rust/nix/pull/997))
++- Added `ptrace::{getregs, setregs}`.
++  ([#1010](https://github.com/nix-rust/nix/pull/1010))
++- Added `nix::sys::signal::signal`.
++  ([#817](https://github.com/nix-rust/nix/pull/817))
++- Added an `mprotect` wrapper.
++  ([#991](https://github.com/nix-rust/nix/pull/991))
++
++### Changed
++### Fixed
++- `lutimes` never worked on OpenBSD as it is not implemented on OpenBSD. It has
++  been removed. ([#1000](https://github.com/nix-rust/nix/pull/1000))
++- `fexecve` never worked on NetBSD or on OpenBSD as it is not implemented on
++  either OS. It has been removed. ([#1000](https://github.com/nix-rust/nix/pull/1000))
++
++### Removed
++
++## [0.12.0] 2018-11-28
++
++### Added
++- Added `FromStr` and `Display` impls for `nix::sys::Signal`
++  ([#884](https://github.com/nix-rust/nix/pull/884))
++- Added a `sync` wrapper.
++  ([#961](https://github.com/nix-rust/nix/pull/961))
++- Added a `sysinfo` wrapper.
++  ([#922](https://github.com/nix-rust/nix/pull/922))
++- Support the `SO_PEERCRED` socket option and the `UnixCredentials` type on all Linux and Android targets.
++  ([#921](https://github.com/nix-rust/nix/pull/921))
++- Added support for `SCM_CREDENTIALS`, allowing to send process credentials over Unix sockets.
++  ([#923](https://github.com/nix-rust/nix/pull/923))
++- Added a `dir` module for reading directories (wraps `fdopendir`, `readdir`, and `rewinddir`).
++  ([#916](https://github.com/nix-rust/nix/pull/916))
++- Added `kmod` module that allows loading and unloading kernel modules on Linux.
++  ([#930](https://github.com/nix-rust/nix/pull/930))
++- Added `futimens` and `utimesat` wrappers ([#944](https://github.com/nix-rust/nix/pull/944)),
++  an `lutimes` wrapper ([#967](https://github.com/nix-rust/nix/pull/967)),
++  and a `utimes` wrapper ([#946](https://github.com/nix-rust/nix/pull/946)).
++- Added `AF_UNSPEC` wrapper to `AddressFamily` ([#948](https://github.com/nix-rust/nix/pull/948))
++- Added the `mode_t` public alias within `sys::stat`.
++  ([#954](https://github.com/nix-rust/nix/pull/954))
++- Added a `truncate` wrapper.
++  ([#956](https://github.com/nix-rust/nix/pull/956))
++- Added a `fchownat` wrapper.
++  ([#955](https://github.com/nix-rust/nix/pull/955))
++- Added support for `ptrace` on BSD operating systems ([#949](https://github.com/nix-rust/nix/pull/949))
++- Added `ptrace` functions for reads and writes to tracee memory and ptrace kill
++  ([#949](https://github.com/nix-rust/nix/pull/949)) ([#958](https://github.com/nix-rust/nix/pull/958))
++- Added a `acct` wrapper module for enabling and disabling process accounting
++  ([#952](https://github.com/nix-rust/nix/pull/952))
++- Added the `time_t` and `suseconds_t` public aliases within `sys::time`.
++  ([#968](https://github.com/nix-rust/nix/pull/968))
++- Added `unistd::execvpe` for Haiku, Linux and OpenBSD
++  ([#975](https://github.com/nix-rust/nix/pull/975))
++- Added `Error::as_errno`.
++  ([#977](https://github.com/nix-rust/nix/pull/977))
++
++### Changed
++- Increased required Rust version to 1.24.1
++  ([#900](https://github.com/nix-rust/nix/pull/900))
++  ([#966](https://github.com/nix-rust/nix/pull/966))
++
++### Fixed
++- Made `preadv` take immutable slice of IoVec.
++  ([#914](https://github.com/nix-rust/nix/pull/914))
++- Fixed passing multiple file descriptors over Unix Sockets.
++  ([#918](https://github.com/nix-rust/nix/pull/918))
++
++### Removed
++
++## [0.11.0] 2018-06-01
++
++### Added
++- Added `sendfile` on FreeBSD and Darwin.
++  ([#901](https://github.com/nix-rust/nix/pull/901))
++- Added `pselect`
++  ([#894](https://github.com/nix-rust/nix/pull/894))
++- Exposed `preadv` and `pwritev` on the BSDs.
++  ([#883](https://github.com/nix-rust/nix/pull/883))
++- Added `mlockall` and `munlockall`
++  ([#876](https://github.com/nix-rust/nix/pull/876))
++- Added `SO_MARK` on Linux.
++  ([#873](https://github.com/nix-rust/nix/pull/873))
++- Added safe support for nearly any buffer type in the `sys::aio` module.
++  ([#872](https://github.com/nix-rust/nix/pull/872))
++- Added `sys::aio::LioCb` as a wrapper for `libc::lio_listio`.
++  ([#872](https://github.com/nix-rust/nix/pull/872))
++- Added `unistd::getsid`
++  ([#850](https://github.com/nix-rust/nix/pull/850))
++- Added `alarm`. ([#830](https://github.com/nix-rust/nix/pull/830))
++- Added interface flags `IFF_NO_PI, IFF_TUN, IFF_TAP` on linux-like systems.
++  ([#853](https://github.com/nix-rust/nix/pull/853))
++- Added `statvfs` module to all MacOS and Linux architectures.
++  ([#832](https://github.com/nix-rust/nix/pull/832))
++- Added `EVFILT_EMPTY`, `EVFILT_PROCDESC`, and `EVFILT_SENDFILE` on FreeBSD.
++  ([#825](https://github.com/nix-rust/nix/pull/825))
++- Exposed `termios::cfmakesane` on FreeBSD.
++  ([#825](https://github.com/nix-rust/nix/pull/825))
++- Exposed `MSG_CMSG_CLOEXEC` on *BSD.
++  ([#825](https://github.com/nix-rust/nix/pull/825))
++- Added `fchmod`, `fchmodat`.
++  ([#857](https://github.com/nix-rust/nix/pull/857))
++- Added `request_code_write_int!` on FreeBSD/DragonFlyBSD
++  ([#833](https://github.com/nix-rust/nix/pull/833))
++
++### Changed
++- `Display` and `Debug` for `SysControlAddr` now includes all fields.
++  ([#837](https://github.com/nix-rust/nix/pull/837))
++- `ioctl!` has been replaced with a family of `ioctl_*!` macros.
++  ([#833](https://github.com/nix-rust/nix/pull/833))
++- `io!`, `ior!`, `iow!`, and `iorw!` has been renamed to `request_code_none!`, `request_code_read!`,
++  `request_code_write!`, and `request_code_readwrite!` respectively. These have also now been exposed
++  in the documentation.
++  ([#833](https://github.com/nix-rust/nix/pull/833))
++- Enabled more `ptrace::Request` definitions for uncommon Linux platforms
++  ([#892](https://github.com/nix-rust/nix/pull/892))
++- Emulation of `FD_CLOEXEC` and `O_NONBLOCK` was removed from `socket()`, `accept4()`, and
++  `socketpair()`.
++  ([#907](https://github.com/nix-rust/nix/pull/907))
++
++### Fixed
++- Fixed possible panics when using `SigAction::flags` on Linux
++  ([#869](https://github.com/nix-rust/nix/pull/869))
++- Properly exposed 460800 and 921600 baud rates on NetBSD
++  ([#837](https://github.com/nix-rust/nix/pull/837))
++- Fixed `ioctl_write_int!` on FreeBSD/DragonFlyBSD
++  ([#833](https://github.com/nix-rust/nix/pull/833))
++- `ioctl_write_int!` now properly supports passing a `c_ulong` as the parameter on Linux non-musl targets
++  ([#833](https://github.com/nix-rust/nix/pull/833))
++
++### Removed
++- Removed explicit support for the `bytes` crate from the `sys::aio` module.
++  See `sys::aio::AioCb::from_boxed_slice` examples for alternatives.
++  ([#872](https://github.com/nix-rust/nix/pull/872))
++- Removed `sys::aio::lio_listio`.  Use `sys::aio::LioCb::listio` instead.
++  ([#872](https://github.com/nix-rust/nix/pull/872))
++- Removed emulated `accept4()` from macos, ios, and netbsd targets
++  ([#907](https://github.com/nix-rust/nix/pull/907))
++- Removed `IFF_NOTRAILERS` on OpenBSD, as it has been removed in OpenBSD 6.3
++  ([#893](https://github.com/nix-rust/nix/pull/893))
++
++## [0.10.0] 2018-01-26
++
++### Added
++- Added specialized wrapper: `sys::ptrace::step`
++  ([#852](https://github.com/nix-rust/nix/pull/852))
++- Added `AioCb::from_ptr` and `AioCb::from_mut_ptr`
++  ([#820](https://github.com/nix-rust/nix/pull/820))
++- Added specialized wrappers: `sys::ptrace::{traceme, syscall, cont, attach}`. Using the matching routines
++  with `sys::ptrace::ptrace` is now deprecated.
++- Added `nix::poll` module for all platforms
++  ([#672](https://github.com/nix-rust/nix/pull/672))
++- Added `nix::ppoll` function for FreeBSD and DragonFly
++  ([#672](https://github.com/nix-rust/nix/pull/672))
++- Added protocol families in `AddressFamily` enum.
++  ([#647](https://github.com/nix-rust/nix/pull/647))
++- Added the `pid()` method to `WaitStatus` for extracting the PID.
++  ([#722](https://github.com/nix-rust/nix/pull/722))
++- Added `nix::unistd:fexecve`.
++  ([#727](https://github.com/nix-rust/nix/pull/727))
++- Expose `uname()` on all platforms.
++  ([#739](https://github.com/nix-rust/nix/pull/739))
++- Expose `signalfd` module on Android as well.
++  ([#739](https://github.com/nix-rust/nix/pull/739))
++- Added `nix::sys::ptrace::detach`.
++  ([#749](https://github.com/nix-rust/nix/pull/749))
++- Added timestamp socket control message variant:
++  `nix::sys::socket::ControlMessage::ScmTimestamp`
++  ([#663](https://github.com/nix-rust/nix/pull/663))
++- Added socket option variant that enables the timestamp socket
++  control message: `nix::sys::socket::sockopt::ReceiveTimestamp`
++  ([#663](https://github.com/nix-rust/nix/pull/663))
++- Added more accessor methods for `AioCb`
++  ([#773](https://github.com/nix-rust/nix/pull/773))
++- Add `nix::sys::fallocate`
++  ([#768](https:://github.com/nix-rust/nix/pull/768))
++- Added `nix::unistd::mkfifo`.
++  ([#602](https://github.com/nix-rust/nix/pull/774))
++- Added `ptrace::Options::PTRACE_O_EXITKILL` on Linux and Android.
++  ([#771](https://github.com/nix-rust/nix/pull/771))
++- Added `nix::sys::uio::{process_vm_readv, process_vm_writev}` on Linux
++  ([#568](https://github.com/nix-rust/nix/pull/568))
++- Added `nix::unistd::{getgroups, setgroups, getgrouplist, initgroups}`. ([#733](https://github.com/nix-rust/nix/pull/733))
++- Added `nix::sys::socket::UnixAddr::as_abstract` on Linux and Android.
++  ([#785](https://github.com/nix-rust/nix/pull/785))
++- Added `nix::unistd::execveat` on Linux and Android.
++  ([#800](https://github.com/nix-rust/nix/pull/800))
++- Added the `from_raw()` method to `WaitStatus` for converting raw status values
++  to `WaitStatus` independent of syscalls.
++  ([#741](https://github.com/nix-rust/nix/pull/741))
++- Added more standard trait implementations for various types.
++  ([#814](https://github.com/nix-rust/nix/pull/814))
++- Added `sigprocmask` to the signal module.
++  ([#826](https://github.com/nix-rust/nix/pull/826))
++- Added `nix::sys::socket::LinkAddr` on Linux and all bsdlike system.
++  ([#813](https://github.com/nix-rust/nix/pull/813))
++- Add socket options for `IP_TRANSPARENT` / `BIND_ANY`.
++  ([#835](https://github.com/nix-rust/nix/pull/835))
++
++### Changed
++- Exposed the `mqueue` module for all supported operating systems.
++  ([#834](https://github.com/nix-rust/nix/pull/834))
++- Use native `pipe2` on all BSD targets.  Users should notice no difference.
++  ([#777](https://github.com/nix-rust/nix/pull/777))
++- Renamed existing `ptrace` wrappers to encourage namespacing ([#692](https://github.com/nix-rust/nix/pull/692))
++- Marked `sys::ptrace::ptrace` as `unsafe`.
++- Changed function signature of `socket()` and `socketpair()`. The `protocol` argument
++  has changed type from `c_int` to `SockProtocol`.
++  It accepts a `None` value for default protocol that was specified with zero using `c_int`.
++  ([#647](https://github.com/nix-rust/nix/pull/647))
++- Made `select` easier to use, adding the ability to automatically calculate the `nfds` parameter using the new
++  `FdSet::highest` ([#701](https://github.com/nix-rust/nix/pull/701))
++- Exposed `unistd::setresuid` and `unistd::setresgid` on FreeBSD and OpenBSD
++  ([#721](https://github.com/nix-rust/nix/pull/721))
++- Refactored the `statvfs` module removing extraneous API functions and the
++  `statvfs::vfs` module. Additionally  `(f)statvfs()` now return the struct
++  directly. And the returned `Statvfs` struct now exposes its data through
++  accessor methods. ([#729](https://github.com/nix-rust/nix/pull/729))
++- The `addr` argument to `madvise` and `msync` is now `*mut` to better match the
++  libc API. ([#731](https://github.com/nix-rust/nix/pull/731))
++- `shm_open` and `shm_unlink` are no longer exposed on Android targets, where
++  they are not officially supported. ([#731](https://github.com/nix-rust/nix/pull/731))
++- `MapFlags`, `MmapAdvise`, and `MsFlags` expose some more variants and only
++  officially-supported variants are provided for each target.
++  ([#731](https://github.com/nix-rust/nix/pull/731))
++- Marked `pty::ptsname` function as `unsafe`
++  ([#744](https://github.com/nix-rust/nix/pull/744))
++- Moved constants ptrace request, event and options to enums and updated ptrace functions and argument types accordingly.
++  ([#749](https://github.com/nix-rust/nix/pull/749))
++- `AioCb::Drop` will now panic if the `AioCb` is still in-progress ([#715](https://github.com/nix-rust/nix/pull/715))
++- Restricted `nix::sys::socket::UnixAddr::new_abstract` to Linux and Android only.
++  ([#785](https://github.com/nix-rust/nix/pull/785))
++- The `ucred` struct has been removed in favor of a `UserCredentials` struct that
++  contains only getters for its fields.
++  ([#814](https://github.com/nix-rust/nix/pull/814))
++- Both `ip_mreq` and `ipv6_mreq` have been replaced with `IpMembershipRequest` and
++  `Ipv6MembershipRequest`.
++  ([#814](https://github.com/nix-rust/nix/pull/814))
++- Removed return type from `pause`.
++  ([#829](https://github.com/nix-rust/nix/pull/829))
++- Changed the termios APIs to allow for using a `u32` instead of the `BaudRate`
++  enum on BSD platforms to support arbitrary baud rates. See the module docs for
++  `nix::sys::termios` for more details.
++  ([#843](https://github.com/nix-rust/nix/pull/843))
++
++### Fixed
++- Fix compilation and tests for OpenBSD targets
++  ([#688](https://github.com/nix-rust/nix/pull/688))
++- Fixed error handling in `AioCb::fsync`, `AioCb::read`, and `AioCb::write`.
++  It is no longer an error to drop an `AioCb` that failed to enqueue in the OS.
++  ([#715](https://github.com/nix-rust/nix/pull/715))
++- Fix potential memory corruption on non-Linux platforms when using
++  `sendmsg`/`recvmsg`, caused by mismatched `msghdr` definition.
++  ([#648](https://github.com/nix-rust/nix/pull/648))
++
++### Removed
++- `AioCb::from_boxed_slice` has been removed.  It was never actually safe.  Use
++  `from_bytes` or `from_bytes_mut` instead.
++  ([#820](https://github.com/nix-rust/nix/pull/820))
++- The syscall module has been removed. This only exposed enough functionality for
++  `memfd_create()` and `pivot_root()`, which are still exposed as separate functions.
++  ([#747](https://github.com/nix-rust/nix/pull/747))
++- The `Errno` variants are no longer reexported from the `errno` module. `Errno` itself is no longer reexported from the
++  crate root and instead must be accessed using the `errno` module. ([#696](https://github.com/nix-rust/nix/pull/696))
++- Removed `MS_VERBOSE`, `MS_NOSEC`, and `MS_BORN` from `MsFlags`. These
++  are internal kernel flags and should never have been exposed.
++  ([#814](https://github.com/nix-rust/nix/pull/814))
++
++
++## [0.9.0] 2017-07-23
++
++### Added
++- Added `sysconf`, `pathconf`, and `fpathconf`
++  ([#630](https://github.com/nix-rust/nix/pull/630)
++- Added `sys::signal::SigAction::{ flags, mask, handler}`
++  ([#611](https://github.com/nix-rust/nix/pull/609)
++- Added `nix::sys::pthread::pthread_self`
++  ([#591](https://github.com/nix-rust/nix/pull/591)
++- Added `AioCb::from_boxed_slice`
++  ([#582](https://github.com/nix-rust/nix/pull/582)
++- Added `nix::unistd::{openat, fstatat, readlink, readlinkat}`
++  ([#551](https://github.com/nix-rust/nix/pull/551))
++- Added `nix::pty::{grantpt, posix_openpt, ptsname/ptsname_r, unlockpt}`
++  ([#556](https://github.com/nix-rust/nix/pull/556)
++- Added `nix::ptr::openpty`
++  ([#456](https://github.com/nix-rust/nix/pull/456))
++- Added `nix::ptrace::{ptrace_get_data, ptrace_getsiginfo, ptrace_setsiginfo
++  and nix::Error::UnsupportedOperation}`
++  ([#614](https://github.com/nix-rust/nix/pull/614))
++- Added `cfmakeraw`, `cfsetspeed`, and `tcgetsid`. ([#527](https://github.com/nix-rust/nix/pull/527))
++- Added "bad none", "bad write_ptr", "bad write_int", and "bad readwrite" variants to the `ioctl!`
++  macro. ([#670](https://github.com/nix-rust/nix/pull/670))
++- On Linux and Android, added support for receiving `PTRACE_O_TRACESYSGOOD`
++  events from `wait` and `waitpid` using `WaitStatus::PtraceSyscall`
++  ([#566](https://github.com/nix-rust/nix/pull/566)).
++
++### Changed
++- The `ioctl!` macro and its variants now allow the generated functions to have
++  doccomments. ([#661](https://github.com/nix-rust/nix/pull/661))
++- Changed `ioctl!(write ...)` into `ioctl!(write_ptr ...)` and `ioctl!(write_int ..)` variants
++  to more clearly separate those use cases. ([#670](https://github.com/nix-rust/nix/pull/670))
++- Marked `sys::mman::{ mmap, munmap, madvise, munlock, msync }` as unsafe.
++  ([#559](https://github.com/nix-rust/nix/pull/559))
++- Minimum supported Rust version is now 1.13.
++- Removed `revents` argument from `PollFd::new()` as it's an output argument and
++  will be overwritten regardless of value.
++  ([#542](https://github.com/nix-rust/nix/pull/542))
++- Changed type signature of `sys::select::FdSet::contains` to make `self`
++  immutable ([#564](https://github.com/nix-rust/nix/pull/564))
++- Introduced wrapper types for `gid_t`, `pid_t`, and `uid_t` as `Gid`, `Pid`, and `Uid`
++  respectively. Various functions have been changed to use these new types as
++  arguments. ([#629](https://github.com/nix-rust/nix/pull/629))
++- Fixed compilation on all Android and iOS targets ([#527](https://github.com/nix-rust/nix/pull/527))
++  and promoted them to Tier 2 support.
++- `nix::sys::statfs::{statfs,fstatfs}` uses statfs definition from `libc::statfs` instead of own linux specific type `nix::sys::Statfs`.
++  Also file system type constants like `nix::sys::statfs::ADFS_SUPER_MAGIC` were removed in favor of the libc equivalent.
++  ([#561](https://github.com/nix-rust/nix/pull/561))
++- Revised the termios API including additional tests and documentation and exposed it on iOS. ([#527](https://github.com/nix-rust/nix/pull/527))
++- `eventfd`, `signalfd`, and `pwritev`/`preadv` functionality is now included by default for all
++  supported platforms. ([#681](https://github.com/nix-rust/nix/pull/561))
++- The `ioctl!` macro's plain variants has been replaced with "bad read" to be consistent with
++  other variants. The generated functions also have more strict types for their arguments. The
++  "*_buf" variants also now calculate total array size and take slice references for improved type
++  safety. The documentation has also been dramatically improved.
++  ([#670](https://github.com/nix-rust/nix/pull/670))
++
++### Removed
++- Removed `io::Error` from `nix::Error` and the conversion from `nix::Error` to `Errno`
++  ([#614](https://github.com/nix-rust/nix/pull/614))
++- All feature flags have been removed in favor of conditional compilation on supported platforms.
++  `execvpe` is no longer supported, but this was already broken and will be added back in the next
++  release. ([#681](https://github.com/nix-rust/nix/pull/561))
++- Removed `ioc_*` functions and many helper constants and macros within the `ioctl` module. These
++  should always have been private and only the `ioctl!` should be used in public code.
++  ([#670](https://github.com/nix-rust/nix/pull/670))
++
++### Fixed
++- Fixed multiple issues compiling under different archetectures and OSes.
++  Now compiles on Linux/MIPS ([#538](https://github.com/nix-rust/nix/pull/538)),
++  `Linux/PPC` ([#553](https://github.com/nix-rust/nix/pull/553)),
++  `MacOS/x86_64,i686` ([#553](https://github.com/nix-rust/nix/pull/553)),
++  `NetBSD/x64_64` ([#538](https://github.com/nix-rust/nix/pull/538)),
++  `FreeBSD/x86_64,i686` ([#536](https://github.com/nix-rust/nix/pull/536)), and
++  `Android` ([#631](https://github.com/nix-rust/nix/pull/631)).
++- `bind` and `errno_location` now work correctly on `Android`
++  ([#631](https://github.com/nix-rust/nix/pull/631))
++- Added `nix::ptrace` on all Linux-kernel-based platforms
++  [#624](https://github.com/nix-rust/nix/pull/624). Previously it was
++  only available on x86, x86-64, and ARM, and also not on Android.
++- Fixed `sys::socket::sendmsg` with zero entry `cmsgs` parameter.
++  ([#623](https://github.com/nix-rust/nix/pull/623))
++- Multiple constants related to the termios API have now been properly defined for
++  all supported platforms. ([#527](https://github.com/nix-rust/nix/pull/527))
++- `ioctl!` macro now supports working with non-int datatypes and properly supports all platforms.
++  ([#670](https://github.com/nix-rust/nix/pull/670))
++
++## [0.8.1] 2017-04-16
++
++### Fixed
++- Fixed build on FreeBSD. (Cherry-picked
++  [a859ee3c](https://github.com/nix-rust/nix/commit/a859ee3c9396dfdb118fcc2c8ecc697e2d303467))
++
++## [0.8.0] 2017-03-02
++
++### Added
++- Added `::nix::sys::termios::BaudRate` enum to provide portable baudrate
++  values. ([#518](https://github.com/nix-rust/nix/pull/518))
++- Added a new `WaitStatus::PtraceEvent` to support ptrace events on Linux
++  and Android ([#438](https://github.com/nix-rust/nix/pull/438))
++- Added support for POSIX AIO
++  ([#483](https://github.com/nix-rust/nix/pull/483))
++  ([#506](https://github.com/nix-rust/nix/pull/506))
++- Added support for XNU system control sockets
++  ([#478](https://github.com/nix-rust/nix/pull/478))
++- Added support for `ioctl` calls on BSD platforms
++  ([#478](https://github.com/nix-rust/nix/pull/478))
++- Added struct `TimeSpec`
++  ([#475](https://github.com/nix-rust/nix/pull/475))
++  ([#483](https://github.com/nix-rust/nix/pull/483))
++- Added complete definitions for all kqueue-related constants on all supported
++  OSes
++  ([#415](https://github.com/nix-rust/nix/pull/415))
++- Added function `epoll_create1` and bitflags `EpollCreateFlags` in
++  `::nix::sys::epoll` in order to support `::libc::epoll_create1`.
++  ([#410](https://github.com/nix-rust/nix/pull/410))
++- Added `setresuid` and `setresgid` for Linux in `::nix::unistd`
++  ([#448](https://github.com/nix-rust/nix/pull/448))
++- Added `getpgid` in `::nix::unistd`
++  ([#433](https://github.com/nix-rust/nix/pull/433))
++- Added `tcgetpgrp` and `tcsetpgrp` in `::nix::unistd`
++  ([#451](https://github.com/nix-rust/nix/pull/451))
++- Added `CLONE_NEWCGROUP` in `::nix::sched`
++  ([#457](https://github.com/nix-rust/nix/pull/457))
++- Added `getpgrp` in `::nix::unistd`
++  ([#491](https://github.com/nix-rust/nix/pull/491))
++- Added `fchdir` in `::nix::unistd`
++  ([#497](https://github.com/nix-rust/nix/pull/497))
++- Added `major` and `minor` in `::nix::sys::stat` for decomposing `dev_t`
++  ([#508](https://github.com/nix-rust/nix/pull/508))
++- Fixed the style of many bitflags and use `libc` in more places.
++  ([#503](https://github.com/nix-rust/nix/pull/503))
++- Added `ppoll` in `::nix::poll`
++  ([#520](https://github.com/nix-rust/nix/pull/520))
++- Added support for getting and setting pipe size with fcntl(2) on Linux
++  ([#540](https://github.com/nix-rust/nix/pull/540))
++
++### Changed
++- `::nix::sys::termios::{cfgetispeed, cfsetispeed, cfgetospeed, cfsetospeed}`
++  switched  to use `BaudRate` enum from `speed_t`.
++  ([#518](https://github.com/nix-rust/nix/pull/518))
++- `epoll_ctl` now could accept None as argument `event`
++  when op is `EpollOp::EpollCtlDel`.
++  ([#480](https://github.com/nix-rust/nix/pull/480))
++- Removed the `bad` keyword from the `ioctl!` macro
++  ([#478](https://github.com/nix-rust/nix/pull/478))
++- Changed `TimeVal` into an opaque Newtype
++  ([#475](https://github.com/nix-rust/nix/pull/475))
++- `kill`'s signature, defined in `::nix::sys::signal`, changed, so that the
++  signal parameter has type `T: Into<Option<Signal>>`. `None` as an argument
++  for that parameter will result in a 0 passed to libc's `kill`, while a
++  `Some`-argument will result in the previous behavior for the contained
++  `Signal`.
++  ([#445](https://github.com/nix-rust/nix/pull/445))
++- The minimum supported version of rustc is now 1.7.0.
++  ([#444](https://github.com/nix-rust/nix/pull/444))
++- Changed `KEvent` to an opaque structure that may only be modified by its
++  constructor and the `ev_set` method.
++  ([#415](https://github.com/nix-rust/nix/pull/415))
++  ([#442](https://github.com/nix-rust/nix/pull/442))
++  ([#463](https://github.com/nix-rust/nix/pull/463))
++- `pipe2` now calls `libc::pipe2` where available. Previously it was emulated
++  using `pipe`, which meant that setting `O_CLOEXEC` was not atomic.
++  ([#427](https://github.com/nix-rust/nix/pull/427))
++- Renamed `EpollEventKind` to `EpollFlags` in `::nix::sys::epoll` in order for
++  it to conform with our conventions.
++  ([#410](https://github.com/nix-rust/nix/pull/410))
++- `EpollEvent` in `::nix::sys::epoll` is now an opaque proxy for
++  `::libc::epoll_event`. The formerly public field `events` is now be read-only
++  accessible with the new method `events()` of `EpollEvent`. Instances of
++  `EpollEvent` can be constructed using the new method `new()` of EpollEvent.
++  ([#410](https://github.com/nix-rust/nix/pull/410))
++- `SigFlags` in `::nix::sys::signal` has be renamed to `SigmaskHow` and its type
++  has changed from `bitflags` to `enum` in order to conform to our conventions.
++  ([#460](https://github.com/nix-rust/nix/pull/460))
++- `sethostname` now takes a `&str` instead of a `&[u8]` as this provides an API
++  that makes more sense in normal, correct usage of the API.
++- `gethostname` previously did not expose the actual length of the hostname
++  written from the underlying system call at all.  This has been updated to
++  return a `&CStr` within the provided buffer that is always properly
++  NUL-terminated (this is not guaranteed by the call with all platforms/libc
++  implementations).
++- Exposed all fcntl(2) operations at the module level, so they can be
++  imported direclty instead of via `FcntlArg` enum.
++  ([#541](https://github.com/nix-rust/nix/pull/541))
++
++### Fixed
++- Fixed multiple issues with Unix domain sockets on non-Linux OSes
++  ([#474](https://github.com/nix-rust/nix/pull/415))
++- Fixed using kqueue with `EVFILT_USER` on FreeBSD
++  ([#415](https://github.com/nix-rust/nix/pull/415))
++- Fixed the build on FreeBSD, and fixed the getsockopt, sendmsg, and recvmsg
++  functions on that same OS.
++  ([#397](https://github.com/nix-rust/nix/pull/397))
++- Fixed an off-by-one bug in `UnixAddr::new_abstract` in `::nix::sys::socket`.
++  ([#429](https://github.com/nix-rust/nix/pull/429))
++- Fixed clone passing a potentially unaligned stack.
++  ([#490](https://github.com/nix-rust/nix/pull/490))
++- Fixed mkdev not creating a `dev_t` the same way as libc.
++  ([#508](https://github.com/nix-rust/nix/pull/508))
++
++## [0.7.0] 2016-09-09
++
++### Added
++- Added `lseek` and `lseek64` in `::nix::unistd`
++  ([#377](https://github.com/nix-rust/nix/pull/377))
++- Added `mkdir` and `getcwd` in `::nix::unistd`
++  ([#416](https://github.com/nix-rust/nix/pull/416))
++- Added accessors `sigmask_mut` and `sigmask` to `UContext` in
++  `::nix::ucontext`.
++  ([#370](https://github.com/nix-rust/nix/pull/370))
++- Added `WUNTRACED` to `WaitPidFlag` in `::nix::sys::wait` for non-_linux_
++  targets.
++  ([#379](https://github.com/nix-rust/nix/pull/379))
++- Added new module `::nix::sys::reboot` with enumeration `RebootMode` and
++  functions `reboot` and `set_cad_enabled`. Currently for _linux_ only.
++  ([#386](https://github.com/nix-rust/nix/pull/386))
++- `FdSet` in `::nix::sys::select` now also implements `Clone`.
++  ([#405](https://github.com/nix-rust/nix/pull/405))
++- Added `F_FULLFSYNC` to `FcntlArg` in `::nix::fcntl` for _apple_ targets.
++  ([#407](https://github.com/nix-rust/nix/pull/407))
++- Added `CpuSet::unset` in `::nix::sched`.
++  ([#402](https://github.com/nix-rust/nix/pull/402))
++- Added constructor method `new()` to `PollFd` in `::nix::poll`, in order to
++  allow creation of objects, after removing public access to members.
++  ([#399](https://github.com/nix-rust/nix/pull/399))
++- Added method `revents()` to `PollFd` in `::nix::poll`, in order to provide
++  read access to formerly public member `revents`.
++  ([#399](https://github.com/nix-rust/nix/pull/399))
++- Added `MSG_CMSG_CLOEXEC` to `MsgFlags` in `::nix::sys::socket` for _linux_ only.
++  ([#422](https://github.com/nix-rust/nix/pull/422))
++
++### Changed
++- Replaced the reexported integer constants for signals by the enumeration
++  `Signal` in `::nix::sys::signal`.
++  ([#362](https://github.com/nix-rust/nix/pull/362))
++- Renamed `EventFdFlag` to `EfdFlags` in `::nix::sys::eventfd`.
++  ([#383](https://github.com/nix-rust/nix/pull/383))
++- Changed the result types of `CpuSet::is_set` and `CpuSet::set` in
++  `::nix::sched` to `Result<bool>` and `Result<()>`, respectively. They now
++  return `EINVAL`, if an invalid argument for the `field` parameter is passed.
++  ([#402](https://github.com/nix-rust/nix/pull/402))
++- `MqAttr` in `::nix::mqueue` is now an opaque proxy for `::libc::mq_attr`,
++  which has the same structure as the old `MqAttr`. The field `mq_flags` of
++  `::libc::mq_attr` is readable using the new method `flags()` of `MqAttr`.
++  `MqAttr` also no longer implements `Debug`.
++  ([#392](https://github.com/nix-rust/nix/pull/392))
++- The parameter `msq_prio` of `mq_receive` with type `u32` in `::nix::mqueue`
++  was replaced by a parameter named `msg_prio` with type `&mut u32`, so that
++  the message priority can be obtained by the caller.
++  ([#392](https://github.com/nix-rust/nix/pull/392))
++- The type alias `MQd` in `::nix::queue` was replaced by the type alias
++  `libc::mqd_t`, both of which are aliases for the same type.
++  ([#392](https://github.com/nix-rust/nix/pull/392))
++
++### Removed
++- Type alias `SigNum` from `::nix::sys::signal`.
++  ([#362](https://github.com/nix-rust/nix/pull/362))
++- Type alias `CpuMask` from `::nix::shed`.
++  ([#402](https://github.com/nix-rust/nix/pull/402))
++- Removed public fields from `PollFd` in `::nix::poll`. (See also added method
++  `revents()`.
++  ([#399](https://github.com/nix-rust/nix/pull/399))
++
++### Fixed
++- Fixed the build problem for NetBSD (Note, that we currently do not support
++  it, so it might already be broken again).
++  ([#389](https://github.com/nix-rust/nix/pull/389))
++- Fixed the build on FreeBSD, and fixed the getsockopt, sendmsg, and recvmsg
++  functions on that same OS.
++  ([#397](https://github.com/nix-rust/nix/pull/397))
++
++## [0.6.0] 2016-06-10
++
++### Added
++- Added `gettid` in `::nix::unistd` for _linux_ and _android_.
++  ([#293](https://github.com/nix-rust/nix/pull/293))
++- Some _mips_ support in `::nix::sched` and `::nix::sys::syscall`.
++  ([#301](https://github.com/nix-rust/nix/pull/301))
++- Added `SIGNALFD_SIGINFO_SIZE` in `::nix::sys::signalfd`.
++  ([#309](https://github.com/nix-rust/nix/pull/309))
++- Added new module `::nix::ucontext` with struct `UContext`. Currently for
++  _linux_ only.
++  ([#311](https://github.com/nix-rust/nix/pull/311))
++- Added `EPOLLEXCLUSIVE` to `EpollEventKind` in `::nix::sys::epoll`.
++  ([#330](https://github.com/nix-rust/nix/pull/330))
++- Added `pause` to `::nix::unistd`.
++  ([#336](https://github.com/nix-rust/nix/pull/336))
++- Added `sleep` to `::nix::unistd`.
++  ([#351](https://github.com/nix-rust/nix/pull/351))
++- Added `S_IFDIR`, `S_IFLNK`, `S_IFMT` to `SFlag` in `::nix::sys::stat`.
++  ([#359](https://github.com/nix-rust/nix/pull/359))
++- Added `clear` and `extend` functions to `SigSet`'s implementation in
++  `::nix::sys::signal`.
++  ([#347](https://github.com/nix-rust/nix/pull/347))
++- `sockaddr_storage_to_addr` in `::nix::sys::socket` now supports `sockaddr_nl`
++  on _linux_ and _android_.
++  ([#366](https://github.com/nix-rust/nix/pull/366))
++- Added support for `SO_ORIGINAL_DST` in `::nix::sys::socket` on _linux_.
++  ([#367](https://github.com/nix-rust/nix/pull/367))
++- Added `SIGINFO` in `::nix::sys::signal` for the _macos_ target as well as
++  `SIGPWR` and `SIGSTKFLT` in `::nix::sys::signal` for non-_macos_ targets.
++  ([#361](https://github.com/nix-rust/nix/pull/361))
++
++### Changed
++- Changed the structure `IoVec` in `::nix::sys::uio`.
++  ([#304](https://github.com/nix-rust/nix/pull/304))
++- Replaced `CREATE_NEW_FD` by `SIGNALFD_NEW` in `::nix::sys::signalfd`.
++  ([#309](https://github.com/nix-rust/nix/pull/309))
++- Renamed `SaFlag` to `SaFlags` and `SigFlag` to `SigFlags` in
++  `::nix::sys::signal`.
++  ([#314](https://github.com/nix-rust/nix/pull/314))
++- Renamed `Fork` to `ForkResult` and changed its fields in `::nix::unistd`.
++  ([#332](https://github.com/nix-rust/nix/pull/332))
++- Added the `signal` parameter to `clone`'s signature in `::nix::sched`.
++  ([#344](https://github.com/nix-rust/nix/pull/344))
++- `execv`, `execve`, and `execvp` now return `Result<Void>` instead of
++  `Result<()>` in `::nix::unistd`.
++  ([#357](https://github.com/nix-rust/nix/pull/357))
++
++### Fixed
++- Improved the conversion from `std::net::SocketAddr` to `InetAddr` in
++  `::nix::sys::socket::addr`.
++  ([#335](https://github.com/nix-rust/nix/pull/335))
++
++## [0.5.0] 2016-03-01
+diff --git a/third_party/rust/nix-0.15.0/CONTRIBUTING.md b/third_party/rust/nix-0.15.0/CONTRIBUTING.md
+new file mode 100644
+index 0000000000000..03a1f630dbb06
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/CONTRIBUTING.md
+@@ -0,0 +1,114 @@
++# Contributing to nix
++
++We're really glad you're interested in contributing to nix! This
++document has a few pointers and guidelines to help get you started.
++
++To have a welcoming and inclusive project, nix uses the Rust project's
++[Code of Conduct][conduct]. All contributors are expected to follow it.
++
++[conduct]: https://www.rust-lang.org/conduct.html
++
++
++# Issues
++
++We use GitHub's [issue tracker][issues].
++
++[issues]: https://github.com/nix-rust/nix/issues
++
++
++## Bug reports
++
++Before submitting a new bug report, please [search existing
++issues][issue-search] to see if there's something related. If not, just
++[open a new issue][new-issue]!
++
++As a reminder, the more information you can give in your issue, the
++easier it is to figure out how to fix it. For nix, this will likely
++include the OS and version, and the architecture.
++
++[issue-search]: https://github.com/nix-rust/nix/search?utf8=%E2%9C%93&q=is%3Aissue&type=Issues
++[new-issue]: https://github.com/nix-rust/nix/issues/new
++
++
++## Feature / API requests
++
++If you'd like a new API or feature added, please [open a new
++issue][new-issue] requesting it. As with reporting a bug, the more
++information you can provide, the better.
++
++
++## Labels
++
++We use labels to help manage issues. The structure is modeled after
++[Rust's issue labeling scheme][rust-labels]:
++- **A-**prefixed labels state which area of the project the issue
++  relates to
++- **E-**prefixed labels explain the level of experience necessary to fix the
++  issue
++- **O-**prefixed labels specify the OS for issues that are OS-specific
++- **R-**prefixed labels specify the architecture for issues that are
++  architecture-specific
++
++[rust-labels]: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#issue-triage
++
++
++# Pull requests
++
++GitHub pull requests are the primary mechanism we use to change nix. GitHub itself has
++some [great documentation][pr-docs] on using the Pull Request feature. We use the 'fork and
++pull' model described there.
++
++Please make pull requests against the `master` branch.
++
++If you change the API by way of adding, removing or changing something or if
++you fix a bug, please add an appropriate note to the [change log][cl]. We
++follow the conventions of [Keep A CHANGELOG][kacl].
++
++[cl]: https://github.com/nix-rust/nix/blob/master/CHANGELOG.md
++[kacl]: https://github.com/olivierlacan/keep-a-changelog/tree/18adb5f5be7a898d046f6a4acb93e39dcf40c4ad
++[pr-docs]: https://help.github.com/articles/using-pull-requests/
++
++## Testing
++
++nix has a test suite that you can run with `cargo test`. Ideally, we'd like pull
++requests to include tests where they make sense. For example, when fixing a bug,
++add a test that would have failed without the fix.
++
++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
++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
++[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!
++
++## bors, the bot who merges all the PRs
++
++All pull requests are merged via [bors], an integration bot. After the
++pull request has been reviewed, the reviewer will leave a comment like
++
++> bors r+
++
++to let bors know that it was approved. Then bors will check that it passes
++tests when merged with the latest changes in the `master` branch, and
++merge if the tests succeed.
++
++[bors]: https://bors-ng.github.io/
++
++
++## API conventions
++
++If you're adding a new API, we have a [document with
++conventions][conventions] to use throughout the nix project.
++
++[conventions]: https://github.com/nix-rust/nix/blob/master/CONVENTIONS.md
+diff --git a/third_party/rust/nix-0.15.0/CONVENTIONS.md b/third_party/rust/nix-0.15.0/CONVENTIONS.md
+new file mode 100644
+index 0000000000000..48daa937345d2
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/CONVENTIONS.md
+@@ -0,0 +1,87 @@
++# Conventions
++
++In order to achieve our goal of wrapping [libc][libc] code in idiomatic rust
++constructs with minimal performance overhead, we follow the following
++conventions.
++
++Note that, thus far, not all the code follows these conventions and not all
++conventions we try to follow have been documented here. If you find an instance
++of either, feel free to remedy the flaw by opening a pull request with
++appropriate changes or additions.
++
++## Change Log
++
++We follow the conventions laid out in [Keep A CHANGELOG][kacl].
++
++[kacl]: https://github.com/olivierlacan/keep-a-changelog/tree/18adb5f5be7a898d046f6a4acb93e39dcf40c4ad
++
++## libc constants, functions and structs
++
++We do not define integer constants ourselves, but use or reexport them from the
++[libc crate][libc].
++
++We use the functions exported from [libc][libc] instead of writing our own
++`extern` declarations.
++
++We use the `struct` definitions from [libc][libc] internally instead of writing
++our own. If we want to add methods to a libc type, we use the newtype pattern.
++For example,
++
++```rust
++pub struct SigSet(libc::sigset_t);
++
++impl SigSet {
++    ...
++}
++```
++
++When creating newtypes, we use Rust's `CamelCase` type naming convention.
++
++## Bitflags
++
++Many C functions have flags parameters that are combined from constants using
++bitwise operations. We represent the types of these parameters by types defined
++using our `libc_bitflags!` macro, which is a convenience wrapper around the
++`bitflags!` macro from the [bitflags crate][bitflags] that brings in the
++constant value from `libc`.
++
++We name the type for a set of constants whose element's names start with `FOO_`
++`FooFlags`.
++
++For example,
++
++```rust
++libc_bitflags!{
++    pub struct ProtFlags: libc::c_int {
++        PROT_NONE;
++        PROT_READ;
++        PROT_WRITE;
++        PROT_EXEC;
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        PROT_GROWSDOWN;
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        PROT_GROWSUP;
++    }
++}
++```
++
++
++## Enumerations
++
++We represent sets of constants that are intended as mutually exclusive arguments
++to parameters of functions by [enumerations][enum].
++
++
++## Structures Initialized by libc Functions
++
++Whenever we need to use a [libc][libc] function to properly initialize a
++variable and said function allows us to use uninitialized memory, we use
++[`std::mem::uninitialized`][std_uninitialized] (or [`core::mem::uninitialized`][core_uninitialized])
++when defining the variable. This allows us to avoid the overhead incurred by
++zeroing or otherwise initializing the variable.
++
++[bitflags]: https://crates.io/crates/bitflags/
++[core_uninitialized]: https://doc.rust-lang.org/core/mem/fn.uninitialized.html
++[enum]: https://doc.rust-lang.org/reference.html#enumerations
++[libc]: https://crates.io/crates/libc/
++[std_uninitialized]: https://doc.rust-lang.org/std/mem/fn.uninitialized.html
+diff --git a/third_party/rust/nix-0.15.0/Cargo.toml b/third_party/rust/nix-0.15.0/Cargo.toml
+new file mode 100644
+index 0000000000000..555b99020d68f
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/Cargo.toml
+@@ -0,0 +1,71 @@
++# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
++#
++# When uploading crates to the registry Cargo will automatically
++# "normalize" Cargo.toml files for maximal compatibility
++# with all versions of Cargo and also rewrite `path` dependencies
++# to registry (e.g., crates.io) dependencies
++#
++# If you believe there's an error in this file please file an
++# issue against the rust-lang/cargo repository. If you're
++# editing this file be aware that the upstream Cargo.toml
++# will likely look very different (and much more reasonable)
++
++[package]
++name = "nix"
++version = "0.15.0"
++authors = ["The nix-rust Project Developers"]
++exclude = ["/.gitignore", "/.travis.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"
++
++[[test]]
++name = "test"
++path = "test/test.rs"
++
++[[test]]
++name = "test-aio-drop"
++path = "test/sys/test_aio_drop.rs"
++
++[[test]]
++name = "test-lio-listio-resubmit"
++path = "test/sys/test_lio_listio_resubmit.rs"
++
++[[test]]
++name = "test-mount"
++path = "test/test_mount.rs"
++harness = false
++
++[[test]]
++name = "test-ptymaster-drop"
++path = "test/test_ptymaster_drop.rs"
++[dependencies.bitflags]
++version = "1.0"
++
++[dependencies.cfg-if]
++version = "0.1.2"
++
++[dependencies.libc]
++version = "0.2.60"
++features = ["extra_traits"]
++
++[dependencies.void]
++version = "1.0.2"
++[dev-dependencies.bytes]
++version = "0.4.8"
++
++[dev-dependencies.lazy_static]
++version = "1.2"
++
++[dev-dependencies.rand]
++version = ">= 0.6, < 0.7"
++
++[dev-dependencies.tempfile]
++version = ">= 3.0.5, < 3.0.9"
++[target."cfg(any(target_os = \"android\", target_os = \"linux\"))".dev-dependencies.caps]
++version = "0.3.1"
++[target."cfg(target_os = \"dragonfly\")".build-dependencies.cc]
++version = "1"
++[target."cfg(target_os = \"freebsd\")".dev-dependencies.sysctl]
++version = "0.1"
+diff --git a/third_party/rust/nix-0.15.0/LICENSE b/third_party/rust/nix-0.15.0/LICENSE
+new file mode 100644
+index 0000000000000..aff9096fdf11d
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/LICENSE
+@@ -0,0 +1,21 @@
++The MIT License (MIT)
++
++Copyright (c) 2015 Carl Lerche + nix-rust Authors
++
++Permission is hereby granted, free of charge, to any person obtaining a copy
++of this software and associated documentation files (the "Software"), to deal
++in the Software without restriction, including without limitation the rights
++to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
++copies of the Software, and to permit persons to whom the Software is
++furnished to do so, subject to the following conditions:
++
++The above copyright notice and this permission notice shall be included in
++all copies or substantial portions of the Software.
++
++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
++OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
++THE SOFTWARE.
+diff --git a/third_party/rust/nix-0.15.0/README.md b/third_party/rust/nix-0.15.0/README.md
+new file mode 100644
+index 0000000000000..0e540ba5b968e
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/README.md
+@@ -0,0 +1,111 @@
++# Rust bindings to *nix APIs
++
++[![Build Status](https://travis-ci.org/nix-rust/nix.svg?branch=master)](https://travis-ci.org/nix-rust/nix)
++[![crates.io](http://meritbadge.herokuapp.com/nix)](https://crates.io/crates/nix)
++
++[Documentation (Releases)](https://docs.rs/nix/)
++
++Nix seeks to provide friendly bindings to various *nix platform APIs (Linux, Darwin,
++...). The goal is to not provide a 100% unified interface, but to unify
++what can be while still providing platform specific APIs.
++
++For many system APIs, Nix provides a safe alternative to the unsafe APIs
++exposed by the [libc crate](https://github.com/rust-lang/libc).  This is done by
++wrapping the libc functionality with types/abstractions that enforce legal/safe
++usage.
++
++
++As an example of what Nix provides, examine the differences between what is
++exposed by libc and nix for the
++[gethostname](http://man7.org/linux/man-pages/man2/gethostname.2.html) system
++call:
++
++```rust,ignore
++// libc api (unsafe, requires handling return code/errno)
++pub unsafe extern fn gethostname(name: *mut c_char, len: size_t) -> c_int;
++
++// nix api (returns a nix::Result<CStr>)
++pub fn gethostname<'a>(buffer: &'a mut [u8]) -> Result<&'a CStr>;
++```
++
++## Supported Platforms
++
++nix target support consists of two tiers. While nix attempts to support all
++platforms supported by [libc](https://github.com/rust-lang/libc), only some
++platforms are actively supported due to either technical or manpower
++limitations. Support for platforms is split into three tiers:
++
++  * Tier 1 - Builds and tests for this target are run in CI. Failures of either
++             block the inclusion of new code.
++  * Tier 2 - Builds for this target are run in CI. Failures during the build
++             blocks the inclusion of new code. Tests may be run, but failures
++             in tests don't block the inclusion of new code.
++  * Tier 3 - Builds for this target are run in CI. Failures during the build
++             *do not* block the inclusion of new code. Testing may be run, but
++             failures in tests don't block the inclusion of new code.
++
++The following targets are supported by `nix`:
++
++Tier 1:
++  * 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
++  * mips-unknown-linux-gnu
++  * mips64-unknown-linux-gnuabi64
++  * mips64el-unknown-linux-gnuabi64
++  * mipsel-unknown-linux-gnu
++  * powerpc64-unknown-linux-gnu
++  * powerpc64le-unknown-linux-gnu
++  * x86_64-apple-darwin
++  * x86_64-unknown-freebsd
++  * x86_64-unknown-linux-gnu
++  * x86_64-unknown-linux-musl
++
++Tier 2:
++  * aarch64-apple-ios
++  * aarch64-linux-android
++  * arm-linux-androideabi
++  * arm-unknown-linux-musleabi
++  * armv7-apple-ios
++  * armv7-linux-androideabi
++  * armv7s-apple-ios
++  * i386-apple-ios
++  * i686-linux-android
++  * powerpc-unknown-linux-gnu
++  * s390x-unknown-linux-gnu
++  * x86_64-apple-ios
++  * x86_64-linux-android
++  * x86_64-unknown-netbsd
++
++## Usage
++
++`nix` requires Rust 1.31.0 or newer.
++
++To use `nix`, first add this to your `Cargo.toml`:
++
++```toml
++[dependencies]
++nix = "0.15.0"
++```
++
++Then, add this to your crate root:
++
++```rust,ignore
++extern crate nix;
++```
++
++## Contributing
++
++Contributions are very welcome.  Please See [CONTRIBUTING](CONTRIBUTING.md) for
++additional details.
++
++Feel free to join us in [the nix-rust/nix](https://gitter.im/nix-rust/nix) channel on Gitter to
++discuss `nix` development.
++
++## License
++
++Nix is licensed under the MIT license.  See [LICENSE](LICENSE) for more details.
+diff --git a/third_party/rust/nix/build.rs b/third_party/rust/nix-0.15.0/build.rs
+similarity index 100%
+rename from third_party/rust/nix/build.rs
+rename to third_party/rust/nix-0.15.0/build.rs
+diff --git a/third_party/rust/nix-0.15.0/src/dir.rs b/third_party/rust/nix-0.15.0/src/dir.rs
+new file mode 100644
+index 0000000000000..1820b5330ff60
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/dir.rs
+@@ -0,0 +1,193 @@
++use {Error, NixPath, Result};
++use errno::Errno;
++use fcntl::{self, OFlag};
++use libc;
++use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
++use std::{ffi, ptr};
++use sys;
++
++#[cfg(target_os = "linux")]
++use libc::{dirent64 as dirent, readdir64_r as readdir_r};
++
++#[cfg(not(target_os = "linux"))]
++use libc::{dirent, readdir_r};
++
++/// An open directory.
++///
++/// This is a lower-level interface than `std::fs::ReadDir`. Notable differences:
++///    * can be opened from a file descriptor (as returned by `openat`, perhaps before knowing
++///      if the path represents a file or directory).
++///    * implements `AsRawFd`, so it can be passed to `fstat`, `openat`, etc.
++///      The file descriptor continues to be owned by the `Dir`, so callers must not keep a `RawFd`
++///      after the `Dir` is dropped.
++///    * can be iterated through multiple times without closing and reopening the file
++///      descriptor. Each iteration rewinds when finished.
++///    * 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)]
++pub struct Dir(
++    ptr::NonNull<libc::DIR>
++);
++
++impl Dir {
++    /// Opens the given path as with `fcntl::open`.
++    pub fn open<P: ?Sized + NixPath>(path: &P, oflag: OFlag,
++                                     mode: sys::stat::Mode) -> Result<Self> {
++        let fd = fcntl::open(path, oflag, mode)?;
++        Dir::from_fd(fd)
++    }
++
++    /// Opens the given path as with `fcntl::openat`.
++    pub fn openat<P: ?Sized + NixPath>(dirfd: RawFd, path: &P, oflag: OFlag,
++                                       mode: sys::stat::Mode) -> Result<Self> {
++        let fd = fcntl::openat(dirfd, path, oflag, mode)?;
++        Dir::from_fd(fd)
++    }
++
++    /// Converts from a descriptor-based object, closing the descriptor on success or failure.
++    #[inline]
++    pub fn from<F: IntoRawFd>(fd: F) -> Result<Self> {
++        Dir::from_fd(fd.into_raw_fd())
++    }
++
++    /// Converts from a file descriptor, closing it on success or failure.
++    pub fn from_fd(fd: RawFd) -> Result<Self> {
++        let d = unsafe { libc::fdopendir(fd) };
++        if d.is_null() {
++            let e = Error::last();
++            unsafe { libc::close(fd) };
++            return Err(e);
++        };
++        // Always guaranteed to be non-null by the previous check
++        Ok(Dir(ptr::NonNull::new(d).unwrap()))
++    }
++
++    /// Returns an iterator of `Result<Entry>` which rewinds when finished.
++    pub fn iter(&mut self) -> Iter {
++        Iter(self)
++    }
++}
++
++// `Dir` is not `Sync`. With the current implementation, it could be, but according to
++// https://www.gnu.org/software/libc/manual/html_node/Reading_002fClosing-Directory.html,
++// future versions of POSIX are likely to obsolete `readdir_r` and specify that it's unsafe to
++// call `readdir` simultaneously from multiple threads.
++//
++// `Dir` is safe to pass from one thread to another, as it's not reference-counted.
++unsafe impl Send for Dir {}
++
++impl AsRawFd for Dir {
++    fn as_raw_fd(&self) -> RawFd {
++        unsafe { libc::dirfd(self.0.as_ptr()) }
++    }
++}
++
++impl Drop for Dir {
++    fn drop(&mut self) {
++        unsafe { libc::closedir(self.0.as_ptr()) };
++    }
++}
++
++#[derive(Debug, Eq, Hash, PartialEq)]
++pub struct Iter<'d>(&'d mut Dir);
++
++impl<'d> Iterator for Iter<'d> {
++    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: Entry = Entry(::std::mem::uninitialized());
++            let mut result = ptr::null_mut();
++            if let Err(e) = Errno::result(readdir_r((self.0).0.as_ptr(), &mut ent.0, &mut result)) {
++                return Some(Err(e));
++            }
++            if result == ptr::null_mut() {
++                return None;
++            }
++            assert_eq!(result, &mut ent.0 as *mut dirent);
++            return Some(Ok(ent));
++        }
++    }
++}
++
++impl<'d> Drop for Iter<'d> {
++    fn drop(&mut self) {
++        unsafe { libc::rewinddir((self.0).0.as_ptr()) }
++    }
++}
++
++/// A directory entry, similar to `std::fs::DirEntry`.
++///
++/// Note that unlike the std version, this may represent the `.` or `..` entries.
++#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
++pub struct Entry(dirent);
++
++#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
++pub enum Type {
++    Fifo,
++    CharacterDevice,
++    Directory,
++    BlockDevice,
++    File,
++    Symlink,
++    Socket,
++}
++
++impl Entry {
++    /// Returns the inode number (`d_ino`) of the underlying `dirent`.
++    #[cfg(any(target_os = "android",
++              target_os = "emscripten",
++              target_os = "fuchsia",
++              target_os = "haiku",
++              target_os = "ios",
++              target_os = "l4re",
++              target_os = "linux",
++              target_os = "macos",
++              target_os = "solaris"))]
++    pub fn ino(&self) -> u64 {
++        self.0.d_ino as u64
++    }
++
++    /// Returns the inode number (`d_fileno`) of the underlying `dirent`.
++    #[cfg(not(any(target_os = "android",
++                  target_os = "emscripten",
++                  target_os = "fuchsia",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "l4re",
++                  target_os = "linux",
++                  target_os = "macos",
++                  target_os = "solaris")))]
++    pub fn ino(&self) -> u64 {
++        self.0.d_fileno as u64
++    }
++
++    /// Returns the bare file name of this directory entry without any other leading path component.
++    pub fn file_name(&self) -> &ffi::CStr {
++        unsafe { ::std::ffi::CStr::from_ptr(self.0.d_name.as_ptr()) }
++    }
++
++    /// Returns the type of this directory entry, if known.
++    ///
++    /// See platform `readdir(3)` or `dirent(5)` manpage for when the file type is known;
++    /// notably, some Linux filesystems don't implement this. The caller should use `stat` or
++    /// `fstat` if this returns `None`.
++    pub fn file_type(&self) -> Option<Type> {
++        match self.0.d_type {
++            libc::DT_FIFO => Some(Type::Fifo),
++            libc::DT_CHR => Some(Type::CharacterDevice),
++            libc::DT_DIR => Some(Type::Directory),
++            libc::DT_BLK => Some(Type::BlockDevice),
++            libc::DT_REG => Some(Type::File),
++            libc::DT_LNK => Some(Type::Symlink),
++            libc::DT_SOCK => Some(Type::Socket),
++            /* libc::DT_UNKNOWN | */ _ => None,
++        }
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/errno.rs b/third_party/rust/nix-0.15.0/src/errno.rs
+new file mode 100644
+index 0000000000000..6a2447bc52675
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/errno.rs
+@@ -0,0 +1,1963 @@
++#[cfg(not(target_os = "dragonfly"))]
++use libc;
++use libc::{c_int, c_void};
++use std::{fmt, io, error};
++use {Error, Result};
++
++pub use self::consts::*;
++
++cfg_if! {
++    if #[cfg(any(target_os = "freebsd",
++                 target_os = "ios",
++                 target_os = "macos"))] {
++        unsafe fn errno_location() -> *mut c_int {
++            libc::__error()
++        }
++    } else if #[cfg(target_os = "dragonfly")] {
++        // DragonFly uses a thread-local errno variable, but #[thread_local] is
++        // feature-gated and not available in stable Rust as of this writing
++        // (Rust 1.21.0). We have to use a C extension to access it
++        // (src/errno_dragonfly.c).
++        //
++        // Tracking issue for `thread_local` stabilization:
++        //
++        //     https://github.com/rust-lang/rust/issues/29594
++        //
++        // Once this becomes stable, we can remove build.rs,
++        // src/errno_dragonfly.c, and use:
++        //
++        //     extern { #[thread_local] static errno: c_int; }
++        //
++        #[link(name="errno_dragonfly", kind="static")]
++        extern {
++            pub fn errno_location() -> *mut c_int;
++        }
++    } else if #[cfg(any(target_os = "android",
++                        target_os = "netbsd",
++                        target_os = "openbsd"))] {
++        unsafe fn errno_location() -> *mut c_int {
++            libc::__errno()
++        }
++    } else if #[cfg(target_os = "linux")] {
++        unsafe fn errno_location() -> *mut c_int {
++            libc::__errno_location()
++        }
++    }
++}
++
++/// Sets the platform-specific errno to no-error
++unsafe fn clear() -> () {
++    *errno_location() = 0;
++}
++
++/// Returns the platform-specific value of errno
++pub fn errno() -> i32 {
++    unsafe {
++        (*errno_location()) as i32
++    }
++}
++
++impl Errno {
++    pub fn last() -> Self {
++        last()
++    }
++
++    pub fn desc(self) -> &'static str {
++        desc(self)
++    }
++
++    pub fn from_i32(err: i32) -> Errno {
++        from_i32(err)
++    }
++
++    pub unsafe fn clear() -> () {
++        clear()
++    }
++
++    /// Returns `Ok(value)` if it does not contain the sentinel value. This
++    /// should not be used when `-1` is not the errno sentinel value.
++    pub fn result<S: ErrnoSentinel + PartialEq<S>>(value: S) -> Result<S> {
++        if value == S::sentinel() {
++            Err(Error::Sys(Self::last()))
++        } else {
++            Ok(value)
++        }
++    }
++}
++
++/// The sentinel value indicates that a function failed and more detailed
++/// information about the error can be found in `errno`
++pub trait ErrnoSentinel: Sized {
++    fn sentinel() -> Self;
++}
++
++impl ErrnoSentinel for isize {
++    fn sentinel() -> Self { -1 }
++}
++
++impl ErrnoSentinel for i32 {
++    fn sentinel() -> Self { -1 }
++}
++
++impl ErrnoSentinel for i64 {
++    fn sentinel() -> Self { -1 }
++}
++
++impl ErrnoSentinel for *mut c_void {
++    fn sentinel() -> Self { (-1 as isize) as *mut c_void }
++}
++
++impl ErrnoSentinel for libc::sighandler_t {
++    fn sentinel() -> Self { libc::SIG_ERR }
++}
++
++impl error::Error for Errno {
++    fn description(&self) -> &str {
++        self.desc()
++    }
++}
++
++impl fmt::Display for Errno {
++    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++        write!(f, "{:?}: {}", self, self.desc())
++    }
++}
++
++impl From<Errno> for io::Error {
++    fn from(err: Errno) -> Self {
++        io::Error::from_raw_os_error(err as i32)
++    }
++}
++
++fn last() -> Errno {
++    Errno::from_i32(errno())
++}
++
++fn desc(errno: Errno) -> &'static str {
++    use self::Errno::*;
++    match errno {
++        UnknownErrno    => "Unknown errno",
++        EPERM           => "Operation not permitted",
++        ENOENT          => "No such file or directory",
++        ESRCH           => "No such process",
++        EINTR           => "Interrupted system call",
++        EIO             => "I/O error",
++        ENXIO           => "No such device or address",
++        E2BIG           => "Argument list too long",
++        ENOEXEC         => "Exec format error",
++        EBADF           => "Bad file number",
++        ECHILD          => "No child processes",
++        EAGAIN          => "Try again",
++        ENOMEM          => "Out of memory",
++        EACCES          => "Permission denied",
++        EFAULT          => "Bad address",
++        ENOTBLK         => "Block device required",
++        EBUSY           => "Device or resource busy",
++        EEXIST          => "File exists",
++        EXDEV           => "Cross-device link",
++        ENODEV          => "No such device",
++        ENOTDIR         => "Not a directory",
++        EISDIR          => "Is a directory",
++        EINVAL          => "Invalid argument",
++        ENFILE          => "File table overflow",
++        EMFILE          => "Too many open files",
++        ENOTTY          => "Not a typewriter",
++        ETXTBSY         => "Text file busy",
++        EFBIG           => "File too large",
++        ENOSPC          => "No space left on device",
++        ESPIPE          => "Illegal seek",
++        EROFS           => "Read-only file system",
++        EMLINK          => "Too many links",
++        EPIPE           => "Broken pipe",
++        EDOM            => "Math argument out of domain of func",
++        ERANGE          => "Math result not representable",
++        EDEADLK         => "Resource deadlock would occur",
++        ENAMETOOLONG    => "File name too long",
++        ENOLCK          => "No record locks available",
++        ENOSYS          => "Function not implemented",
++        ENOTEMPTY       => "Directory not empty",
++        ELOOP           => "Too many symbolic links encountered",
++        ENOMSG          => "No message of desired type",
++        EIDRM           => "Identifier removed",
++        EINPROGRESS     => "Operation now in progress",
++        EALREADY        => "Operation already in progress",
++        ENOTSOCK        => "Socket operation on non-socket",
++        EDESTADDRREQ    => "Destination address required",
++        EMSGSIZE        => "Message too long",
++        EPROTOTYPE      => "Protocol wrong type for socket",
++        ENOPROTOOPT     => "Protocol not available",
++        EPROTONOSUPPORT => "Protocol not supported",
++        ESOCKTNOSUPPORT => "Socket type not supported",
++        EPFNOSUPPORT    => "Protocol family not supported",
++        EAFNOSUPPORT    => "Address family not supported by protocol",
++        EADDRINUSE      => "Address already in use",
++        EADDRNOTAVAIL   => "Cannot assign requested address",
++        ENETDOWN        => "Network is down",
++        ENETUNREACH     => "Network is unreachable",
++        ENETRESET       => "Network dropped connection because of reset",
++        ECONNABORTED    => "Software caused connection abort",
++        ECONNRESET      => "Connection reset by peer",
++        ENOBUFS         => "No buffer space available",
++        EISCONN         => "Transport endpoint is already connected",
++        ENOTCONN        => "Transport endpoint is not connected",
++        ESHUTDOWN       => "Cannot send after transport endpoint shutdown",
++        ETOOMANYREFS    => "Too many references: cannot splice",
++        ETIMEDOUT       => "Connection timed out",
++        ECONNREFUSED    => "Connection refused",
++        EHOSTDOWN       => "Host is down",
++        EHOSTUNREACH    => "No route to host",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ECHRNG          => "Channel number out of range",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EL2NSYNC        => "Level 2 not synchronized",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EL3HLT          => "Level 3 halted",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EL3RST          => "Level 3 reset",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ELNRNG          => "Link number out of range",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EUNATCH         => "Protocol driver not attached",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ENOCSI          => "No CSI structure available",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EL2HLT          => "Level 2 halted",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EBADE           => "Invalid exchange",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EBADR           => "Invalid request descriptor",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EXFULL          => "Exchange full",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ENOANO          => "No anode",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EBADRQC         => "Invalid request code",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EBADSLT         => "Invalid slot",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EBFONT          => "Bad font file format",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ENOSTR          => "Device not a stream",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ENODATA         => "No data available",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ETIME           => "Timer expired",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ENOSR           => "Out of streams resources",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ENONET          => "Machine is not on the network",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ENOPKG          => "Package not installed",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EREMOTE         => "Object is remote",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ENOLINK         => "Link has been severed",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EADV            => "Advertise error",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ESRMNT          => "Srmount error",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ECOMM           => "Communication error on send",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EPROTO          => "Protocol error",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EMULTIHOP       => "Multihop attempted",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EDOTDOT         => "RFS specific error",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EBADMSG         => "Not a data message",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EOVERFLOW       => "Value too large for defined data type",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ENOTUNIQ        => "Name not unique on network",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EBADFD          => "File descriptor in bad state",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EREMCHG         => "Remote address changed",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ELIBACC         => "Can not access a needed shared library",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ELIBBAD         => "Accessing a corrupted shared library",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ELIBSCN         => ".lib section in a.out corrupted",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ELIBMAX         => "Attempting to link in too many shared libraries",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ELIBEXEC        => "Cannot exec a shared library directly",
++
++        #[cfg(any(target_os = "linux", target_os = "android", target_os = "openbsd"))]
++        EILSEQ          => "Illegal byte sequence",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ERESTART        => "Interrupted system call should be restarted",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ESTRPIPE        => "Streams pipe error",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EUSERS          => "Too many users",
++
++        #[cfg(any(target_os = "linux", target_os = "android", target_os = "netbsd"))]
++        EOPNOTSUPP      => "Operation not supported on transport endpoint",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ESTALE          => "Stale file handle",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EUCLEAN         => "Structure needs cleaning",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ENOTNAM         => "Not a XENIX named type file",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ENAVAIL         => "No XENIX semaphores available",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EISNAM          => "Is a named type file",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EREMOTEIO       => "Remote I/O error",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EDQUOT          => "Quota exceeded",
++
++        #[cfg(any(target_os = "linux", target_os = "android",
++                  target_os = "openbsd", target_os = "dragonfly"))]
++        ENOMEDIUM       => "No medium found",
++
++        #[cfg(any(target_os = "linux", target_os = "android", target_os = "openbsd"))]
++        EMEDIUMTYPE     => "Wrong medium type",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ECANCELED       => "Operation canceled",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ENOKEY          => "Required key not available",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EKEYEXPIRED     => "Key has expired",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EKEYREVOKED     => "Key has been revoked",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EKEYREJECTED    => "Key was rejected by service",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        EOWNERDEAD      => "Owner died",
++
++        #[cfg(any(target_os = "linux", target_os = "android"))]
++        ENOTRECOVERABLE => "State not recoverable",
++
++        #[cfg(all(target_os = "linux", not(target_arch="mips")))]
++        ERFKILL         => "Operation not possible due to RF-kill",
++
++        #[cfg(all(target_os = "linux", not(target_arch="mips")))]
++        EHWPOISON       => "Memory page has hardware error",
++
++        #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++        EDOOFUS         => "Programming error",
++
++        #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++        EMULTIHOP       => "Multihop attempted",
++
++        #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++        ENOLINK         => "Link has been severed",
++
++        #[cfg(target_os = "freebsd")]
++        ENOTCAPABLE     => "Capabilities insufficient",
++
++        #[cfg(target_os = "freebsd")]
++        ECAPMODE        => "Not permitted in capability mode",
++
++        #[cfg(any(target_os = "macos", target_os = "freebsd",
++                  target_os = "dragonfly", target_os = "ios",
++                  target_os = "openbsd", target_os = "netbsd"))]
++        ENEEDAUTH       => "Need authenticator",
++
++        #[cfg(any(target_os = "macos", target_os = "freebsd",
++                  target_os = "dragonfly", target_os = "ios",
++                  target_os = "openbsd", target_os = "netbsd"))]
++        EOVERFLOW       => "Value too large to be stored in data type",
++
++        #[cfg(any(target_os = "macos", target_os = "freebsd",
++                  target_os = "dragonfly", target_os = "ios",
++                  target_os = "netbsd"))]
++        EILSEQ          => "Illegal byte sequence",
++
++        #[cfg(any(target_os = "macos", target_os = "freebsd",
++                  target_os = "dragonfly", target_os = "ios",
++                  target_os = "openbsd", target_os = "netbsd"))]
++        ENOATTR         => "Attribute not found",
++
++        #[cfg(any(target_os = "macos", target_os = "freebsd",
++                  target_os = "dragonfly", target_os = "ios",
++                  target_os = "openbsd", target_os = "netbsd"))]
++        EBADMSG         => "Bad message",
++
++        #[cfg(any(target_os = "macos", target_os = "freebsd",
++                  target_os = "dragonfly", target_os = "ios",
++                  target_os = "openbsd", target_os = "netbsd"))]
++        EPROTO          => "Protocol error",
++
++        #[cfg(any(target_os = "macos", target_os = "freebsd",
++                  target_os = "ios", target_os = "openbsd", ))]
++        ENOTRECOVERABLE => "State not recoverable",
++
++        #[cfg(any(target_os = "macos", target_os = "freebsd",
++                  target_os = "ios", target_os = "openbsd"))]
++        EOWNERDEAD      => "Previous owner died",
++
++        #[cfg(any(target_os = "macos", target_os = "freebsd",
++                  target_os = "dragonfly", target_os = "ios",
++                  target_os = "openbsd", target_os = "netbsd"))]
++        ENOTSUP         => "Operation not supported",
++
++        #[cfg(any(target_os = "macos", target_os = "freebsd",
++                  target_os = "dragonfly", target_os = "ios",
++                  target_os = "openbsd", target_os = "netbsd"))]
++        EPROCLIM        => "Too many processes",
++
++        #[cfg(any(target_os = "macos", target_os = "freebsd",
++                  target_os = "dragonfly", target_os = "ios",
++                  target_os = "openbsd", target_os = "netbsd"))]
++        EUSERS          => "Too many users",
++
++        #[cfg(any(target_os = "macos", target_os = "freebsd",
++                  target_os = "dragonfly", target_os = "ios",
++                  target_os = "openbsd", target_os = "netbsd"))]
++        EDQUOT          => "Disc quota exceeded",
++
++        #[cfg(any(target_os = "macos", target_os = "freebsd",
++                  target_os = "dragonfly", target_os = "ios",
++                  target_os = "openbsd", target_os = "netbsd"))]
++        ESTALE          => "Stale NFS file handle",
++
++        #[cfg(any(target_os = "macos", target_os = "freebsd",
++                  target_os = "dragonfly", target_os = "ios",
++                  target_os = "openbsd", target_os = "netbsd"))]
++        EREMOTE         => "Too many levels of remote in path",
++
++        #[cfg(any(target_os = "macos", target_os = "freebsd",
++                  target_os = "dragonfly", target_os = "ios",
++                  target_os = "openbsd", target_os = "netbsd"))]
++        EBADRPC         => "RPC struct is bad",
++
++        #[cfg(any(target_os = "macos", target_os = "freebsd",
++                  target_os = "dragonfly", target_os = "ios",
++                  target_os = "openbsd", target_os = "netbsd"))]
++        ERPCMISMATCH    => "RPC version wrong",
++
++        #[cfg(any(target_os = "macos", target_os = "freebsd",
++                  target_os = "dragonfly", target_os = "ios",
++                  target_os = "openbsd", target_os = "netbsd"))]
++        EPROGUNAVAIL    => "RPC prog. not avail",
++
++        #[cfg(any(target_os = "macos", target_os = "freebsd",
++                  target_os = "dragonfly", target_os = "ios",
++                  target_os = "openbsd", target_os = "netbsd"))]
++        EPROGMISMATCH   => "Program version wrong",
++
++        #[cfg(any(target_os = "macos", target_os = "freebsd",
++                  target_os = "dragonfly", target_os = "ios",
++                  target_os = "openbsd", target_os = "netbsd"))]
++        EPROCUNAVAIL    => "Bad procedure for program",
++
++        #[cfg(any(target_os = "macos", target_os = "freebsd",
++                  target_os = "dragonfly", target_os = "ios",
++                  target_os = "openbsd", target_os = "netbsd"))]
++        EFTYPE          => "Inappropriate file type or format",
++
++        #[cfg(any(target_os = "macos", target_os = "freebsd",
++                  target_os = "dragonfly", target_os = "ios",
++                  target_os = "openbsd", target_os = "netbsd"))]
++        EAUTH           => "Authentication error",
++
++        #[cfg(any(target_os = "macos", target_os = "freebsd",
++                  target_os = "dragonfly", target_os = "ios",
++                  target_os = "openbsd", target_os = "netbsd"))]
++        ECANCELED       => "Operation canceled",
++
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        EPWROFF         => "Device power is off",
++
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        EDEVERR         => "Device error, e.g. paper out",
++
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        EBADEXEC        => "Bad executable",
++
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        EBADARCH        => "Bad CPU type in executable",
++
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        ESHLIBVERS      => "Shared library version mismatch",
++
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        EBADMACHO       => "Malformed Macho file",
++
++        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
++        EMULTIHOP       => "Reserved",
++
++        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
++        ENODATA         => "No message available on STREAM",
++
++        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
++        ENOLINK         => "Reserved",
++
++        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
++        ENOSR           => "No STREAM resources",
++
++        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
++        ENOSTR          => "Not a STREAM",
++
++        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
++        ETIME           => "STREAM ioctl timeout",
++
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        EOPNOTSUPP      => "Operation not supported on socket",
++
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        ENOPOLICY       => "No such policy registered",
++
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        EQFULL          => "Interface output queue is full",
++
++        #[cfg(target_os = "openbsd")]
++        EOPNOTSUPP      => "Operation not supported",
++
++        #[cfg(target_os = "openbsd")]
++        EIPSEC          => "IPsec processing failure",
++
++        #[cfg(target_os = "dragonfly")]
++        EASYNC          => "Async",
++    }
++}
++
++#[cfg(any(target_os = "linux", target_os = "android"))]
++mod consts {
++    use libc;
++
++    #[derive(Clone, Copy, Debug, Eq, PartialEq)]
++    #[repr(i32)]
++    pub enum Errno {
++        UnknownErrno    = 0,
++        EPERM           = libc::EPERM,
++        ENOENT          = libc::ENOENT,
++        ESRCH           = libc::ESRCH,
++        EINTR           = libc::EINTR,
++        EIO             = libc::EIO,
++        ENXIO           = libc::ENXIO,
++        E2BIG           = libc::E2BIG,
++        ENOEXEC         = libc::ENOEXEC,
++        EBADF           = libc::EBADF,
++        ECHILD          = libc::ECHILD,
++        EAGAIN          = libc::EAGAIN,
++        ENOMEM          = libc::ENOMEM,
++        EACCES          = libc::EACCES,
++        EFAULT          = libc::EFAULT,
++        ENOTBLK         = libc::ENOTBLK,
++        EBUSY           = libc::EBUSY,
++        EEXIST          = libc::EEXIST,
++        EXDEV           = libc::EXDEV,
++        ENODEV          = libc::ENODEV,
++        ENOTDIR         = libc::ENOTDIR,
++        EISDIR          = libc::EISDIR,
++        EINVAL          = libc::EINVAL,
++        ENFILE          = libc::ENFILE,
++        EMFILE          = libc::EMFILE,
++        ENOTTY          = libc::ENOTTY,
++        ETXTBSY         = libc::ETXTBSY,
++        EFBIG           = libc::EFBIG,
++        ENOSPC          = libc::ENOSPC,
++        ESPIPE          = libc::ESPIPE,
++        EROFS           = libc::EROFS,
++        EMLINK          = libc::EMLINK,
++        EPIPE           = libc::EPIPE,
++        EDOM            = libc::EDOM,
++        ERANGE          = libc::ERANGE,
++        EDEADLK         = libc::EDEADLK,
++        ENAMETOOLONG    = libc::ENAMETOOLONG,
++        ENOLCK          = libc::ENOLCK,
++        ENOSYS          = libc::ENOSYS,
++        ENOTEMPTY       = libc::ENOTEMPTY,
++        ELOOP           = libc::ELOOP,
++        ENOMSG          = libc::ENOMSG,
++        EIDRM           = libc::EIDRM,
++        ECHRNG          = libc::ECHRNG,
++        EL2NSYNC        = libc::EL2NSYNC,
++        EL3HLT          = libc::EL3HLT,
++        EL3RST          = libc::EL3RST,
++        ELNRNG          = libc::ELNRNG,
++        EUNATCH         = libc::EUNATCH,
++        ENOCSI          = libc::ENOCSI,
++        EL2HLT          = libc::EL2HLT,
++        EBADE           = libc::EBADE,
++        EBADR           = libc::EBADR,
++        EXFULL          = libc::EXFULL,
++        ENOANO          = libc::ENOANO,
++        EBADRQC         = libc::EBADRQC,
++        EBADSLT         = libc::EBADSLT,
++        EBFONT          = libc::EBFONT,
++        ENOSTR          = libc::ENOSTR,
++        ENODATA         = libc::ENODATA,
++        ETIME           = libc::ETIME,
++        ENOSR           = libc::ENOSR,
++        ENONET          = libc::ENONET,
++        ENOPKG          = libc::ENOPKG,
++        EREMOTE         = libc::EREMOTE,
++        ENOLINK         = libc::ENOLINK,
++        EADV            = libc::EADV,
++        ESRMNT          = libc::ESRMNT,
++        ECOMM           = libc::ECOMM,
++        EPROTO          = libc::EPROTO,
++        EMULTIHOP       = libc::EMULTIHOP,
++        EDOTDOT         = libc::EDOTDOT,
++        EBADMSG         = libc::EBADMSG,
++        EOVERFLOW       = libc::EOVERFLOW,
++        ENOTUNIQ        = libc::ENOTUNIQ,
++        EBADFD          = libc::EBADFD,
++        EREMCHG         = libc::EREMCHG,
++        ELIBACC         = libc::ELIBACC,
++        ELIBBAD         = libc::ELIBBAD,
++        ELIBSCN         = libc::ELIBSCN,
++        ELIBMAX         = libc::ELIBMAX,
++        ELIBEXEC        = libc::ELIBEXEC,
++        EILSEQ          = libc::EILSEQ,
++        ERESTART        = libc::ERESTART,
++        ESTRPIPE        = libc::ESTRPIPE,
++        EUSERS          = libc::EUSERS,
++        ENOTSOCK        = libc::ENOTSOCK,
++        EDESTADDRREQ    = libc::EDESTADDRREQ,
++        EMSGSIZE        = libc::EMSGSIZE,
++        EPROTOTYPE      = libc::EPROTOTYPE,
++        ENOPROTOOPT     = libc::ENOPROTOOPT,
++        EPROTONOSUPPORT = libc::EPROTONOSUPPORT,
++        ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT,
++        EOPNOTSUPP      = libc::EOPNOTSUPP,
++        EPFNOSUPPORT    = libc::EPFNOSUPPORT,
++        EAFNOSUPPORT    = libc::EAFNOSUPPORT,
++        EADDRINUSE      = libc::EADDRINUSE,
++        EADDRNOTAVAIL   = libc::EADDRNOTAVAIL,
++        ENETDOWN        = libc::ENETDOWN,
++        ENETUNREACH     = libc::ENETUNREACH,
++        ENETRESET       = libc::ENETRESET,
++        ECONNABORTED    = libc::ECONNABORTED,
++        ECONNRESET      = libc::ECONNRESET,
++        ENOBUFS         = libc::ENOBUFS,
++        EISCONN         = libc::EISCONN,
++        ENOTCONN        = libc::ENOTCONN,
++        ESHUTDOWN       = libc::ESHUTDOWN,
++        ETOOMANYREFS    = libc::ETOOMANYREFS,
++        ETIMEDOUT       = libc::ETIMEDOUT,
++        ECONNREFUSED    = libc::ECONNREFUSED,
++        EHOSTDOWN       = libc::EHOSTDOWN,
++        EHOSTUNREACH    = libc::EHOSTUNREACH,
++        EALREADY        = libc::EALREADY,
++        EINPROGRESS     = libc::EINPROGRESS,
++        ESTALE          = libc::ESTALE,
++        EUCLEAN         = libc::EUCLEAN,
++        ENOTNAM         = libc::ENOTNAM,
++        ENAVAIL         = libc::ENAVAIL,
++        EISNAM          = libc::EISNAM,
++        EREMOTEIO       = libc::EREMOTEIO,
++        EDQUOT          = libc::EDQUOT,
++        ENOMEDIUM       = libc::ENOMEDIUM,
++        EMEDIUMTYPE     = libc::EMEDIUMTYPE,
++        ECANCELED       = libc::ECANCELED,
++        ENOKEY          = libc::ENOKEY,
++        EKEYEXPIRED     = libc::EKEYEXPIRED,
++        EKEYREVOKED     = libc::EKEYREVOKED,
++        EKEYREJECTED    = libc::EKEYREJECTED,
++        EOWNERDEAD      = libc::EOWNERDEAD,
++        ENOTRECOVERABLE = libc::ENOTRECOVERABLE,
++        #[cfg(not(any(target_os = "android", target_arch="mips")))]
++        ERFKILL         = libc::ERFKILL,
++        #[cfg(not(any(target_os = "android", target_arch="mips")))]
++        EHWPOISON       = libc::EHWPOISON,
++    }
++
++    pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
++    pub const EDEADLOCK:   Errno = Errno::EDEADLK;
++    pub const ENOTSUP:     Errno = Errno::EOPNOTSUPP;
++
++    pub fn from_i32(e: i32) -> Errno {
++        use self::Errno::*;
++
++        match e {
++            libc::EPERM => EPERM,
++            libc::ENOENT => ENOENT,
++            libc::ESRCH => ESRCH,
++            libc::EINTR => EINTR,
++            libc::EIO => EIO,
++            libc::ENXIO => ENXIO,
++            libc::E2BIG => E2BIG,
++            libc::ENOEXEC => ENOEXEC,
++            libc::EBADF => EBADF,
++            libc::ECHILD => ECHILD,
++            libc::EAGAIN => EAGAIN,
++            libc::ENOMEM => ENOMEM,
++            libc::EACCES => EACCES,
++            libc::EFAULT => EFAULT,
++            libc::ENOTBLK => ENOTBLK,
++            libc::EBUSY => EBUSY,
++            libc::EEXIST => EEXIST,
++            libc::EXDEV => EXDEV,
++            libc::ENODEV => ENODEV,
++            libc::ENOTDIR => ENOTDIR,
++            libc::EISDIR => EISDIR,
++            libc::EINVAL => EINVAL,
++            libc::ENFILE => ENFILE,
++            libc::EMFILE => EMFILE,
++            libc::ENOTTY => ENOTTY,
++            libc::ETXTBSY => ETXTBSY,
++            libc::EFBIG => EFBIG,
++            libc::ENOSPC => ENOSPC,
++            libc::ESPIPE => ESPIPE,
++            libc::EROFS => EROFS,
++            libc::EMLINK => EMLINK,
++            libc::EPIPE => EPIPE,
++            libc::EDOM => EDOM,
++            libc::ERANGE => ERANGE,
++            libc::EDEADLK => EDEADLK,
++            libc::ENAMETOOLONG => ENAMETOOLONG,
++            libc::ENOLCK => ENOLCK,
++            libc::ENOSYS => ENOSYS,
++            libc::ENOTEMPTY => ENOTEMPTY,
++            libc::ELOOP => ELOOP,
++            libc::ENOMSG => ENOMSG,
++            libc::EIDRM => EIDRM,
++            libc::ECHRNG => ECHRNG,
++            libc::EL2NSYNC => EL2NSYNC,
++            libc::EL3HLT => EL3HLT,
++            libc::EL3RST => EL3RST,
++            libc::ELNRNG => ELNRNG,
++            libc::EUNATCH => EUNATCH,
++            libc::ENOCSI => ENOCSI,
++            libc::EL2HLT => EL2HLT,
++            libc::EBADE => EBADE,
++            libc::EBADR => EBADR,
++            libc::EXFULL => EXFULL,
++            libc::ENOANO => ENOANO,
++            libc::EBADRQC => EBADRQC,
++            libc::EBADSLT => EBADSLT,
++            libc::EBFONT => EBFONT,
++            libc::ENOSTR => ENOSTR,
++            libc::ENODATA => ENODATA,
++            libc::ETIME => ETIME,
++            libc::ENOSR => ENOSR,
++            libc::ENONET => ENONET,
++            libc::ENOPKG => ENOPKG,
++            libc::EREMOTE => EREMOTE,
++            libc::ENOLINK => ENOLINK,
++            libc::EADV => EADV,
++            libc::ESRMNT => ESRMNT,
++            libc::ECOMM => ECOMM,
++            libc::EPROTO => EPROTO,
++            libc::EMULTIHOP => EMULTIHOP,
++            libc::EDOTDOT => EDOTDOT,
++            libc::EBADMSG => EBADMSG,
++            libc::EOVERFLOW => EOVERFLOW,
++            libc::ENOTUNIQ => ENOTUNIQ,
++            libc::EBADFD => EBADFD,
++            libc::EREMCHG => EREMCHG,
++            libc::ELIBACC => ELIBACC,
++            libc::ELIBBAD => ELIBBAD,
++            libc::ELIBSCN => ELIBSCN,
++            libc::ELIBMAX => ELIBMAX,
++            libc::ELIBEXEC => ELIBEXEC,
++            libc::EILSEQ => EILSEQ,
++            libc::ERESTART => ERESTART,
++            libc::ESTRPIPE => ESTRPIPE,
++            libc::EUSERS => EUSERS,
++            libc::ENOTSOCK => ENOTSOCK,
++            libc::EDESTADDRREQ => EDESTADDRREQ,
++            libc::EMSGSIZE => EMSGSIZE,
++            libc::EPROTOTYPE => EPROTOTYPE,
++            libc::ENOPROTOOPT => ENOPROTOOPT,
++            libc::EPROTONOSUPPORT => EPROTONOSUPPORT,
++            libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT,
++            libc::EOPNOTSUPP => EOPNOTSUPP,
++            libc::EPFNOSUPPORT => EPFNOSUPPORT,
++            libc::EAFNOSUPPORT => EAFNOSUPPORT,
++            libc::EADDRINUSE => EADDRINUSE,
++            libc::EADDRNOTAVAIL => EADDRNOTAVAIL,
++            libc::ENETDOWN => ENETDOWN,
++            libc::ENETUNREACH => ENETUNREACH,
++            libc::ENETRESET => ENETRESET,
++            libc::ECONNABORTED => ECONNABORTED,
++            libc::ECONNRESET => ECONNRESET,
++            libc::ENOBUFS => ENOBUFS,
++            libc::EISCONN => EISCONN,
++            libc::ENOTCONN => ENOTCONN,
++            libc::ESHUTDOWN => ESHUTDOWN,
++            libc::ETOOMANYREFS => ETOOMANYREFS,
++            libc::ETIMEDOUT => ETIMEDOUT,
++            libc::ECONNREFUSED => ECONNREFUSED,
++            libc::EHOSTDOWN => EHOSTDOWN,
++            libc::EHOSTUNREACH => EHOSTUNREACH,
++            libc::EALREADY => EALREADY,
++            libc::EINPROGRESS => EINPROGRESS,
++            libc::ESTALE => ESTALE,
++            libc::EUCLEAN => EUCLEAN,
++            libc::ENOTNAM => ENOTNAM,
++            libc::ENAVAIL => ENAVAIL,
++            libc::EISNAM => EISNAM,
++            libc::EREMOTEIO => EREMOTEIO,
++            libc::EDQUOT => EDQUOT,
++            libc::ENOMEDIUM => ENOMEDIUM,
++            libc::EMEDIUMTYPE => EMEDIUMTYPE,
++            libc::ECANCELED => ECANCELED,
++            libc::ENOKEY => ENOKEY,
++            libc::EKEYEXPIRED => EKEYEXPIRED,
++            libc::EKEYREVOKED => EKEYREVOKED,
++            libc::EKEYREJECTED => EKEYREJECTED,
++            libc::EOWNERDEAD => EOWNERDEAD,
++            libc::ENOTRECOVERABLE => ENOTRECOVERABLE,
++            #[cfg(not(any(target_os = "android", target_arch="mips")))]
++            libc::ERFKILL => ERFKILL,
++            #[cfg(not(any(target_os = "android", target_arch="mips")))]
++            libc::EHWPOISON => EHWPOISON,
++            _   => UnknownErrno,
++        }
++    }
++}
++
++#[cfg(any(target_os = "macos", target_os = "ios"))]
++mod consts {
++    use libc;
++
++    #[derive(Clone, Copy, Debug, Eq, PartialEq)]
++    #[repr(i32)]
++    pub enum Errno {
++        UnknownErrno    = 0,
++        EPERM           = libc::EPERM,
++        ENOENT          = libc::ENOENT,
++        ESRCH           = libc::ESRCH,
++        EINTR           = libc::EINTR,
++        EIO             = libc::EIO,
++        ENXIO           = libc::ENXIO,
++        E2BIG           = libc::E2BIG,
++        ENOEXEC         = libc::ENOEXEC,
++        EBADF           = libc::EBADF,
++        ECHILD          = libc::ECHILD,
++        EDEADLK         = libc::EDEADLK,
++        ENOMEM          = libc::ENOMEM,
++        EACCES          = libc::EACCES,
++        EFAULT          = libc::EFAULT,
++        ENOTBLK         = libc::ENOTBLK,
++        EBUSY           = libc::EBUSY,
++        EEXIST          = libc::EEXIST,
++        EXDEV           = libc::EXDEV,
++        ENODEV          = libc::ENODEV,
++        ENOTDIR         = libc::ENOTDIR,
++        EISDIR          = libc::EISDIR,
++        EINVAL          = libc::EINVAL,
++        ENFILE          = libc::ENFILE,
++        EMFILE          = libc::EMFILE,
++        ENOTTY          = libc::ENOTTY,
++        ETXTBSY         = libc::ETXTBSY,
++        EFBIG           = libc::EFBIG,
++        ENOSPC          = libc::ENOSPC,
++        ESPIPE          = libc::ESPIPE,
++        EROFS           = libc::EROFS,
++        EMLINK          = libc::EMLINK,
++        EPIPE           = libc::EPIPE,
++        EDOM            = libc::EDOM,
++        ERANGE          = libc::ERANGE,
++        EAGAIN          = libc::EAGAIN,
++        EINPROGRESS     = libc::EINPROGRESS,
++        EALREADY        = libc::EALREADY,
++        ENOTSOCK        = libc::ENOTSOCK,
++        EDESTADDRREQ    = libc::EDESTADDRREQ,
++        EMSGSIZE        = libc::EMSGSIZE,
++        EPROTOTYPE      = libc::EPROTOTYPE,
++        ENOPROTOOPT     = libc::ENOPROTOOPT,
++        EPROTONOSUPPORT = libc::EPROTONOSUPPORT,
++        ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT,
++        ENOTSUP         = libc::ENOTSUP,
++        EPFNOSUPPORT    = libc::EPFNOSUPPORT,
++        EAFNOSUPPORT    = libc::EAFNOSUPPORT,
++        EADDRINUSE      = libc::EADDRINUSE,
++        EADDRNOTAVAIL   = libc::EADDRNOTAVAIL,
++        ENETDOWN        = libc::ENETDOWN,
++        ENETUNREACH     = libc::ENETUNREACH,
++        ENETRESET       = libc::ENETRESET,
++        ECONNABORTED    = libc::ECONNABORTED,
++        ECONNRESET      = libc::ECONNRESET,
++        ENOBUFS         = libc::ENOBUFS,
++        EISCONN         = libc::EISCONN,
++        ENOTCONN        = libc::ENOTCONN,
++        ESHUTDOWN       = libc::ESHUTDOWN,
++        ETOOMANYREFS    = libc::ETOOMANYREFS,
++        ETIMEDOUT       = libc::ETIMEDOUT,
++        ECONNREFUSED    = libc::ECONNREFUSED,
++        ELOOP           = libc::ELOOP,
++        ENAMETOOLONG    = libc::ENAMETOOLONG,
++        EHOSTDOWN       = libc::EHOSTDOWN,
++        EHOSTUNREACH    = libc::EHOSTUNREACH,
++        ENOTEMPTY       = libc::ENOTEMPTY,
++        EPROCLIM        = libc::EPROCLIM,
++        EUSERS          = libc::EUSERS,
++        EDQUOT          = libc::EDQUOT,
++        ESTALE          = libc::ESTALE,
++        EREMOTE         = libc::EREMOTE,
++        EBADRPC         = libc::EBADRPC,
++        ERPCMISMATCH    = libc::ERPCMISMATCH,
++        EPROGUNAVAIL    = libc::EPROGUNAVAIL,
++        EPROGMISMATCH   = libc::EPROGMISMATCH,
++        EPROCUNAVAIL    = libc::EPROCUNAVAIL,
++        ENOLCK          = libc::ENOLCK,
++        ENOSYS          = libc::ENOSYS,
++        EFTYPE          = libc::EFTYPE,
++        EAUTH           = libc::EAUTH,
++        ENEEDAUTH       = libc::ENEEDAUTH,
++        EPWROFF         = libc::EPWROFF,
++        EDEVERR         = libc::EDEVERR,
++        EOVERFLOW       = libc::EOVERFLOW,
++        EBADEXEC        = libc::EBADEXEC,
++        EBADARCH        = libc::EBADARCH,
++        ESHLIBVERS      = libc::ESHLIBVERS,
++        EBADMACHO       = libc::EBADMACHO,
++        ECANCELED       = libc::ECANCELED,
++        EIDRM           = libc::EIDRM,
++        ENOMSG          = libc::ENOMSG,
++        EILSEQ          = libc::EILSEQ,
++        ENOATTR         = libc::ENOATTR,
++        EBADMSG         = libc::EBADMSG,
++        EMULTIHOP       = libc::EMULTIHOP,
++        ENODATA         = libc::ENODATA,
++        ENOLINK         = libc::ENOLINK,
++        ENOSR           = libc::ENOSR,
++        ENOSTR          = libc::ENOSTR,
++        EPROTO          = libc::EPROTO,
++        ETIME           = libc::ETIME,
++        EOPNOTSUPP      = libc::EOPNOTSUPP,
++        ENOPOLICY       = libc::ENOPOLICY,
++        ENOTRECOVERABLE = libc::ENOTRECOVERABLE,
++        EOWNERDEAD      = libc::EOWNERDEAD,
++        EQFULL          = libc::EQFULL,
++    }
++
++    pub const ELAST: Errno       = Errno::EQFULL;
++    pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
++    pub const EDEADLOCK:   Errno = Errno::EDEADLK;
++
++    pub const EL2NSYNC: Errno = Errno::UnknownErrno;
++
++    pub fn from_i32(e: i32) -> Errno {
++        use self::Errno::*;
++
++        match e {
++            libc::EPERM => EPERM,
++            libc::ENOENT => ENOENT,
++            libc::ESRCH => ESRCH,
++            libc::EINTR => EINTR,
++            libc::EIO => EIO,
++            libc::ENXIO => ENXIO,
++            libc::E2BIG => E2BIG,
++            libc::ENOEXEC => ENOEXEC,
++            libc::EBADF => EBADF,
++            libc::ECHILD => ECHILD,
++            libc::EDEADLK => EDEADLK,
++            libc::ENOMEM => ENOMEM,
++            libc::EACCES => EACCES,
++            libc::EFAULT => EFAULT,
++            libc::ENOTBLK => ENOTBLK,
++            libc::EBUSY => EBUSY,
++            libc::EEXIST => EEXIST,
++            libc::EXDEV => EXDEV,
++            libc::ENODEV => ENODEV,
++            libc::ENOTDIR => ENOTDIR,
++            libc::EISDIR => EISDIR,
++            libc::EINVAL => EINVAL,
++            libc::ENFILE => ENFILE,
++            libc::EMFILE => EMFILE,
++            libc::ENOTTY => ENOTTY,
++            libc::ETXTBSY => ETXTBSY,
++            libc::EFBIG => EFBIG,
++            libc::ENOSPC => ENOSPC,
++            libc::ESPIPE => ESPIPE,
++            libc::EROFS => EROFS,
++            libc::EMLINK => EMLINK,
++            libc::EPIPE => EPIPE,
++            libc::EDOM => EDOM,
++            libc::ERANGE => ERANGE,
++            libc::EAGAIN => EAGAIN,
++            libc::EINPROGRESS => EINPROGRESS,
++            libc::EALREADY => EALREADY,
++            libc::ENOTSOCK => ENOTSOCK,
++            libc::EDESTADDRREQ => EDESTADDRREQ,
++            libc::EMSGSIZE => EMSGSIZE,
++            libc::EPROTOTYPE => EPROTOTYPE,
++            libc::ENOPROTOOPT => ENOPROTOOPT,
++            libc::EPROTONOSUPPORT => EPROTONOSUPPORT,
++            libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT,
++            libc::ENOTSUP => ENOTSUP,
++            libc::EPFNOSUPPORT => EPFNOSUPPORT,
++            libc::EAFNOSUPPORT => EAFNOSUPPORT,
++            libc::EADDRINUSE => EADDRINUSE,
++            libc::EADDRNOTAVAIL => EADDRNOTAVAIL,
++            libc::ENETDOWN => ENETDOWN,
++            libc::ENETUNREACH => ENETUNREACH,
++            libc::ENETRESET => ENETRESET,
++            libc::ECONNABORTED => ECONNABORTED,
++            libc::ECONNRESET => ECONNRESET,
++            libc::ENOBUFS => ENOBUFS,
++            libc::EISCONN => EISCONN,
++            libc::ENOTCONN => ENOTCONN,
++            libc::ESHUTDOWN => ESHUTDOWN,
++            libc::ETOOMANYREFS => ETOOMANYREFS,
++            libc::ETIMEDOUT => ETIMEDOUT,
++            libc::ECONNREFUSED => ECONNREFUSED,
++            libc::ELOOP => ELOOP,
++            libc::ENAMETOOLONG => ENAMETOOLONG,
++            libc::EHOSTDOWN => EHOSTDOWN,
++            libc::EHOSTUNREACH => EHOSTUNREACH,
++            libc::ENOTEMPTY => ENOTEMPTY,
++            libc::EPROCLIM => EPROCLIM,
++            libc::EUSERS => EUSERS,
++            libc::EDQUOT => EDQUOT,
++            libc::ESTALE => ESTALE,
++            libc::EREMOTE => EREMOTE,
++            libc::EBADRPC => EBADRPC,
++            libc::ERPCMISMATCH => ERPCMISMATCH,
++            libc::EPROGUNAVAIL => EPROGUNAVAIL,
++            libc::EPROGMISMATCH => EPROGMISMATCH,
++            libc::EPROCUNAVAIL => EPROCUNAVAIL,
++            libc::ENOLCK => ENOLCK,
++            libc::ENOSYS => ENOSYS,
++            libc::EFTYPE => EFTYPE,
++            libc::EAUTH => EAUTH,
++            libc::ENEEDAUTH => ENEEDAUTH,
++            libc::EPWROFF => EPWROFF,
++            libc::EDEVERR => EDEVERR,
++            libc::EOVERFLOW => EOVERFLOW,
++            libc::EBADEXEC => EBADEXEC,
++            libc::EBADARCH => EBADARCH,
++            libc::ESHLIBVERS => ESHLIBVERS,
++            libc::EBADMACHO => EBADMACHO,
++            libc::ECANCELED => ECANCELED,
++            libc::EIDRM => EIDRM,
++            libc::ENOMSG => ENOMSG,
++            libc::EILSEQ => EILSEQ,
++            libc::ENOATTR => ENOATTR,
++            libc::EBADMSG => EBADMSG,
++            libc::EMULTIHOP => EMULTIHOP,
++            libc::ENODATA => ENODATA,
++            libc::ENOLINK => ENOLINK,
++            libc::ENOSR => ENOSR,
++            libc::ENOSTR => ENOSTR,
++            libc::EPROTO => EPROTO,
++            libc::ETIME => ETIME,
++            libc::EOPNOTSUPP => EOPNOTSUPP,
++            libc::ENOPOLICY => ENOPOLICY,
++            libc::ENOTRECOVERABLE => ENOTRECOVERABLE,
++            libc::EOWNERDEAD => EOWNERDEAD,
++            libc::EQFULL => EQFULL,
++            _   => UnknownErrno,
++        }
++    }
++}
++
++#[cfg(target_os = "freebsd")]
++mod consts {
++    use libc;
++
++    #[derive(Clone, Copy, Debug, Eq, PartialEq)]
++    #[repr(i32)]
++    pub enum Errno {
++        UnknownErrno    = 0,
++        EPERM           = libc::EPERM,
++        ENOENT          = libc::ENOENT,
++        ESRCH           = libc::ESRCH,
++        EINTR           = libc::EINTR,
++        EIO             = libc::EIO,
++        ENXIO           = libc::ENXIO,
++        E2BIG           = libc::E2BIG,
++        ENOEXEC         = libc::ENOEXEC,
++        EBADF           = libc::EBADF,
++        ECHILD          = libc::ECHILD,
++        EDEADLK         = libc::EDEADLK,
++        ENOMEM          = libc::ENOMEM,
++        EACCES          = libc::EACCES,
++        EFAULT          = libc::EFAULT,
++        ENOTBLK         = libc::ENOTBLK,
++        EBUSY           = libc::EBUSY,
++        EEXIST          = libc::EEXIST,
++        EXDEV           = libc::EXDEV,
++        ENODEV          = libc::ENODEV,
++        ENOTDIR         = libc::ENOTDIR,
++        EISDIR          = libc::EISDIR,
++        EINVAL          = libc::EINVAL,
++        ENFILE          = libc::ENFILE,
++        EMFILE          = libc::EMFILE,
++        ENOTTY          = libc::ENOTTY,
++        ETXTBSY         = libc::ETXTBSY,
++        EFBIG           = libc::EFBIG,
++        ENOSPC          = libc::ENOSPC,
++        ESPIPE          = libc::ESPIPE,
++        EROFS           = libc::EROFS,
++        EMLINK          = libc::EMLINK,
++        EPIPE           = libc::EPIPE,
++        EDOM            = libc::EDOM,
++        ERANGE          = libc::ERANGE,
++        EAGAIN          = libc::EAGAIN,
++        EINPROGRESS     = libc::EINPROGRESS,
++        EALREADY        = libc::EALREADY,
++        ENOTSOCK        = libc::ENOTSOCK,
++        EDESTADDRREQ    = libc::EDESTADDRREQ,
++        EMSGSIZE        = libc::EMSGSIZE,
++        EPROTOTYPE      = libc::EPROTOTYPE,
++        ENOPROTOOPT     = libc::ENOPROTOOPT,
++        EPROTONOSUPPORT = libc::EPROTONOSUPPORT,
++        ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT,
++        ENOTSUP         = libc::ENOTSUP,
++        EPFNOSUPPORT    = libc::EPFNOSUPPORT,
++        EAFNOSUPPORT    = libc::EAFNOSUPPORT,
++        EADDRINUSE      = libc::EADDRINUSE,
++        EADDRNOTAVAIL   = libc::EADDRNOTAVAIL,
++        ENETDOWN        = libc::ENETDOWN,
++        ENETUNREACH     = libc::ENETUNREACH,
++        ENETRESET       = libc::ENETRESET,
++        ECONNABORTED    = libc::ECONNABORTED,
++        ECONNRESET      = libc::ECONNRESET,
++        ENOBUFS         = libc::ENOBUFS,
++        EISCONN         = libc::EISCONN,
++        ENOTCONN        = libc::ENOTCONN,
++        ESHUTDOWN       = libc::ESHUTDOWN,
++        ETOOMANYREFS    = libc::ETOOMANYREFS,
++        ETIMEDOUT       = libc::ETIMEDOUT,
++        ECONNREFUSED    = libc::ECONNREFUSED,
++        ELOOP           = libc::ELOOP,
++        ENAMETOOLONG    = libc::ENAMETOOLONG,
++        EHOSTDOWN       = libc::EHOSTDOWN,
++        EHOSTUNREACH    = libc::EHOSTUNREACH,
++        ENOTEMPTY       = libc::ENOTEMPTY,
++        EPROCLIM        = libc::EPROCLIM,
++        EUSERS          = libc::EUSERS,
++        EDQUOT          = libc::EDQUOT,
++        ESTALE          = libc::ESTALE,
++        EREMOTE         = libc::EREMOTE,
++        EBADRPC         = libc::EBADRPC,
++        ERPCMISMATCH    = libc::ERPCMISMATCH,
++        EPROGUNAVAIL    = libc::EPROGUNAVAIL,
++        EPROGMISMATCH   = libc::EPROGMISMATCH,
++        EPROCUNAVAIL    = libc::EPROCUNAVAIL,
++        ENOLCK          = libc::ENOLCK,
++        ENOSYS          = libc::ENOSYS,
++        EFTYPE          = libc::EFTYPE,
++        EAUTH           = libc::EAUTH,
++        ENEEDAUTH       = libc::ENEEDAUTH,
++        EIDRM           = libc::EIDRM,
++        ENOMSG          = libc::ENOMSG,
++        EOVERFLOW       = libc::EOVERFLOW,
++        ECANCELED       = libc::ECANCELED,
++        EILSEQ          = libc::EILSEQ,
++        ENOATTR         = libc::ENOATTR,
++        EDOOFUS         = libc::EDOOFUS,
++        EBADMSG         = libc::EBADMSG,
++        EMULTIHOP       = libc::EMULTIHOP,
++        ENOLINK         = libc::ENOLINK,
++        EPROTO          = libc::EPROTO,
++        ENOTCAPABLE     = libc::ENOTCAPABLE,
++        ECAPMODE        = libc::ECAPMODE,
++        ENOTRECOVERABLE = libc::ENOTRECOVERABLE,
++        EOWNERDEAD      = libc::EOWNERDEAD,
++    }
++
++    pub const ELAST: Errno       = Errno::EOWNERDEAD;
++    pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
++    pub const EDEADLOCK:   Errno = Errno::EDEADLK;
++
++    pub const EL2NSYNC: Errno = Errno::UnknownErrno;
++
++    pub fn from_i32(e: i32) -> Errno {
++        use self::Errno::*;
++
++        match e {
++            libc::EPERM => EPERM,
++            libc::ENOENT => ENOENT,
++            libc::ESRCH => ESRCH,
++            libc::EINTR => EINTR,
++            libc::EIO => EIO,
++            libc::ENXIO => ENXIO,
++            libc::E2BIG => E2BIG,
++            libc::ENOEXEC => ENOEXEC,
++            libc::EBADF => EBADF,
++            libc::ECHILD => ECHILD,
++            libc::EDEADLK => EDEADLK,
++            libc::ENOMEM => ENOMEM,
++            libc::EACCES => EACCES,
++            libc::EFAULT => EFAULT,
++            libc::ENOTBLK => ENOTBLK,
++            libc::EBUSY => EBUSY,
++            libc::EEXIST => EEXIST,
++            libc::EXDEV => EXDEV,
++            libc::ENODEV => ENODEV,
++            libc::ENOTDIR => ENOTDIR,
++            libc::EISDIR => EISDIR,
++            libc::EINVAL => EINVAL,
++            libc::ENFILE => ENFILE,
++            libc::EMFILE => EMFILE,
++            libc::ENOTTY => ENOTTY,
++            libc::ETXTBSY => ETXTBSY,
++            libc::EFBIG => EFBIG,
++            libc::ENOSPC => ENOSPC,
++            libc::ESPIPE => ESPIPE,
++            libc::EROFS => EROFS,
++            libc::EMLINK => EMLINK,
++            libc::EPIPE => EPIPE,
++            libc::EDOM => EDOM,
++            libc::ERANGE => ERANGE,
++            libc::EAGAIN => EAGAIN,
++            libc::EINPROGRESS => EINPROGRESS,
++            libc::EALREADY => EALREADY,
++            libc::ENOTSOCK => ENOTSOCK,
++            libc::EDESTADDRREQ => EDESTADDRREQ,
++            libc::EMSGSIZE => EMSGSIZE,
++            libc::EPROTOTYPE => EPROTOTYPE,
++            libc::ENOPROTOOPT => ENOPROTOOPT,
++            libc::EPROTONOSUPPORT => EPROTONOSUPPORT,
++            libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT,
++            libc::ENOTSUP => ENOTSUP,
++            libc::EPFNOSUPPORT => EPFNOSUPPORT,
++            libc::EAFNOSUPPORT => EAFNOSUPPORT,
++            libc::EADDRINUSE => EADDRINUSE,
++            libc::EADDRNOTAVAIL => EADDRNOTAVAIL,
++            libc::ENETDOWN => ENETDOWN,
++            libc::ENETUNREACH => ENETUNREACH,
++            libc::ENETRESET => ENETRESET,
++            libc::ECONNABORTED => ECONNABORTED,
++            libc::ECONNRESET => ECONNRESET,
++            libc::ENOBUFS => ENOBUFS,
++            libc::EISCONN => EISCONN,
++            libc::ENOTCONN => ENOTCONN,
++            libc::ESHUTDOWN => ESHUTDOWN,
++            libc::ETOOMANYREFS => ETOOMANYREFS,
++            libc::ETIMEDOUT => ETIMEDOUT,
++            libc::ECONNREFUSED => ECONNREFUSED,
++            libc::ELOOP => ELOOP,
++            libc::ENAMETOOLONG => ENAMETOOLONG,
++            libc::EHOSTDOWN => EHOSTDOWN,
++            libc::EHOSTUNREACH => EHOSTUNREACH,
++            libc::ENOTEMPTY => ENOTEMPTY,
++            libc::EPROCLIM => EPROCLIM,
++            libc::EUSERS => EUSERS,
++            libc::EDQUOT => EDQUOT,
++            libc::ESTALE => ESTALE,
++            libc::EREMOTE => EREMOTE,
++            libc::EBADRPC => EBADRPC,
++            libc::ERPCMISMATCH => ERPCMISMATCH,
++            libc::EPROGUNAVAIL => EPROGUNAVAIL,
++            libc::EPROGMISMATCH => EPROGMISMATCH,
++            libc::EPROCUNAVAIL => EPROCUNAVAIL,
++            libc::ENOLCK => ENOLCK,
++            libc::ENOSYS => ENOSYS,
++            libc::EFTYPE => EFTYPE,
++            libc::EAUTH => EAUTH,
++            libc::ENEEDAUTH => ENEEDAUTH,
++            libc::EIDRM => EIDRM,
++            libc::ENOMSG => ENOMSG,
++            libc::EOVERFLOW => EOVERFLOW,
++            libc::ECANCELED => ECANCELED,
++            libc::EILSEQ => EILSEQ,
++            libc::ENOATTR => ENOATTR,
++            libc::EDOOFUS => EDOOFUS,
++            libc::EBADMSG => EBADMSG,
++            libc::EMULTIHOP => EMULTIHOP,
++            libc::ENOLINK => ENOLINK,
++            libc::EPROTO => EPROTO,
++            libc::ENOTCAPABLE => ENOTCAPABLE,
++            libc::ECAPMODE => ECAPMODE,
++            libc::ENOTRECOVERABLE => ENOTRECOVERABLE,
++            libc::EOWNERDEAD => EOWNERDEAD,
++            _   => UnknownErrno,
++        }
++    }
++}
++
++
++#[cfg(target_os = "dragonfly")]
++mod consts {
++    use libc;
++
++    #[derive(Clone, Copy, Debug, Eq, PartialEq)]
++    #[repr(i32)]
++    pub enum Errno {
++        UnknownErrno    = 0,
++        EPERM           = libc::EPERM,
++        ENOENT          = libc::ENOENT,
++        ESRCH           = libc::ESRCH,
++        EINTR           = libc::EINTR,
++        EIO             = libc::EIO,
++        ENXIO           = libc::ENXIO,
++        E2BIG           = libc::E2BIG,
++        ENOEXEC         = libc::ENOEXEC,
++        EBADF           = libc::EBADF,
++        ECHILD          = libc::ECHILD,
++        EDEADLK         = libc::EDEADLK,
++        ENOMEM          = libc::ENOMEM,
++        EACCES          = libc::EACCES,
++        EFAULT          = libc::EFAULT,
++        ENOTBLK         = libc::ENOTBLK,
++        EBUSY           = libc::EBUSY,
++        EEXIST          = libc::EEXIST,
++        EXDEV           = libc::EXDEV,
++        ENODEV          = libc::ENODEV,
++        ENOTDIR         = libc::ENOTDIR,
++        EISDIR          = libc::EISDIR,
++        EINVAL          = libc::EINVAL,
++        ENFILE          = libc::ENFILE,
++        EMFILE          = libc::EMFILE,
++        ENOTTY          = libc::ENOTTY,
++        ETXTBSY         = libc::ETXTBSY,
++        EFBIG           = libc::EFBIG,
++        ENOSPC          = libc::ENOSPC,
++        ESPIPE          = libc::ESPIPE,
++        EROFS           = libc::EROFS,
++        EMLINK          = libc::EMLINK,
++        EPIPE           = libc::EPIPE,
++        EDOM            = libc::EDOM,
++        ERANGE          = libc::ERANGE,
++        EAGAIN          = libc::EAGAIN,
++        EINPROGRESS     = libc::EINPROGRESS,
++        EALREADY        = libc::EALREADY,
++        ENOTSOCK        = libc::ENOTSOCK,
++        EDESTADDRREQ    = libc::EDESTADDRREQ,
++        EMSGSIZE        = libc::EMSGSIZE,
++        EPROTOTYPE      = libc::EPROTOTYPE,
++        ENOPROTOOPT     = libc::ENOPROTOOPT,
++        EPROTONOSUPPORT = libc::EPROTONOSUPPORT,
++        ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT,
++        ENOTSUP         = libc::ENOTSUP,
++        EPFNOSUPPORT    = libc::EPFNOSUPPORT,
++        EAFNOSUPPORT    = libc::EAFNOSUPPORT,
++        EADDRINUSE      = libc::EADDRINUSE,
++        EADDRNOTAVAIL   = libc::EADDRNOTAVAIL,
++        ENETDOWN        = libc::ENETDOWN,
++        ENETUNREACH     = libc::ENETUNREACH,
++        ENETRESET       = libc::ENETRESET,
++        ECONNABORTED    = libc::ECONNABORTED,
++        ECONNRESET      = libc::ECONNRESET,
++        ENOBUFS         = libc::ENOBUFS,
++        EISCONN         = libc::EISCONN,
++        ENOTCONN        = libc::ENOTCONN,
++        ESHUTDOWN       = libc::ESHUTDOWN,
++        ETOOMANYREFS    = libc::ETOOMANYREFS,
++        ETIMEDOUT       = libc::ETIMEDOUT,
++        ECONNREFUSED    = libc::ECONNREFUSED,
++        ELOOP           = libc::ELOOP,
++        ENAMETOOLONG    = libc::ENAMETOOLONG,
++        EHOSTDOWN       = libc::EHOSTDOWN,
++        EHOSTUNREACH    = libc::EHOSTUNREACH,
++        ENOTEMPTY       = libc::ENOTEMPTY,
++        EPROCLIM        = libc::EPROCLIM,
++        EUSERS          = libc::EUSERS,
++        EDQUOT          = libc::EDQUOT,
++        ESTALE          = libc::ESTALE,
++        EREMOTE         = libc::EREMOTE,
++        EBADRPC         = libc::EBADRPC,
++        ERPCMISMATCH    = libc::ERPCMISMATCH,
++        EPROGUNAVAIL    = libc::EPROGUNAVAIL,
++        EPROGMISMATCH   = libc::EPROGMISMATCH,
++        EPROCUNAVAIL    = libc::EPROCUNAVAIL,
++        ENOLCK          = libc::ENOLCK,
++        ENOSYS          = libc::ENOSYS,
++        EFTYPE          = libc::EFTYPE,
++        EAUTH           = libc::EAUTH,
++        ENEEDAUTH       = libc::ENEEDAUTH,
++        EIDRM           = libc::EIDRM,
++        ENOMSG          = libc::ENOMSG,
++        EOVERFLOW       = libc::EOVERFLOW,
++        ECANCELED       = libc::ECANCELED,
++        EILSEQ          = libc::EILSEQ,
++        ENOATTR         = libc::ENOATTR,
++        EDOOFUS         = libc::EDOOFUS,
++        EBADMSG         = libc::EBADMSG,
++        EMULTIHOP       = libc::EMULTIHOP,
++        ENOLINK         = libc::ENOLINK,
++        EPROTO          = libc::EPROTO,
++        ENOMEDIUM       = libc::ENOMEDIUM,
++        EASYNC          = libc::EASYNC,
++    }
++
++    pub const ELAST: Errno       = Errno::EASYNC;
++    pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
++    pub const EDEADLOCK:   Errno = Errno::EDEADLK;
++    pub const EOPNOTSUPP:  Errno = Errno::ENOTSUP;
++
++    pub const EL2NSYNC: Errno = Errno::UnknownErrno;
++
++    pub fn from_i32(e: i32) -> Errno {
++        use self::Errno::*;
++
++        match e {
++            libc::EPERM => EPERM,
++            libc::ENOENT => ENOENT,
++            libc::ESRCH => ESRCH,
++            libc::EINTR => EINTR,
++            libc::EIO => EIO,
++            libc::ENXIO => ENXIO,
++            libc::E2BIG => E2BIG,
++            libc::ENOEXEC => ENOEXEC,
++            libc::EBADF => EBADF,
++            libc::ECHILD => ECHILD,
++            libc::EDEADLK => EDEADLK,
++            libc::ENOMEM => ENOMEM,
++            libc::EACCES => EACCES,
++            libc::EFAULT => EFAULT,
++            libc::ENOTBLK => ENOTBLK,
++            libc::EBUSY => EBUSY,
++            libc::EEXIST => EEXIST,
++            libc::EXDEV => EXDEV,
++            libc::ENODEV => ENODEV,
++            libc::ENOTDIR => ENOTDIR,
++            libc::EISDIR=> EISDIR,
++            libc::EINVAL => EINVAL,
++            libc::ENFILE => ENFILE,
++            libc::EMFILE => EMFILE,
++            libc::ENOTTY => ENOTTY,
++            libc::ETXTBSY => ETXTBSY,
++            libc::EFBIG => EFBIG,
++            libc::ENOSPC => ENOSPC,
++            libc::ESPIPE => ESPIPE,
++            libc::EROFS => EROFS,
++            libc::EMLINK => EMLINK,
++            libc::EPIPE => EPIPE,
++            libc::EDOM => EDOM,
++            libc::ERANGE => ERANGE,
++            libc::EAGAIN => EAGAIN,
++            libc::EINPROGRESS => EINPROGRESS,
++            libc::EALREADY => EALREADY,
++            libc::ENOTSOCK => ENOTSOCK,
++            libc::EDESTADDRREQ => EDESTADDRREQ,
++            libc::EMSGSIZE => EMSGSIZE,
++            libc::EPROTOTYPE => EPROTOTYPE,
++            libc::ENOPROTOOPT => ENOPROTOOPT,
++            libc::EPROTONOSUPPORT => EPROTONOSUPPORT,
++            libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT,
++            libc::ENOTSUP => ENOTSUP,
++            libc::EPFNOSUPPORT => EPFNOSUPPORT,
++            libc::EAFNOSUPPORT => EAFNOSUPPORT,
++            libc::EADDRINUSE => EADDRINUSE,
++            libc::EADDRNOTAVAIL => EADDRNOTAVAIL,
++            libc::ENETDOWN => ENETDOWN,
++            libc::ENETUNREACH => ENETUNREACH,
++            libc::ENETRESET => ENETRESET,
++            libc::ECONNABORTED => ECONNABORTED,
++            libc::ECONNRESET => ECONNRESET,
++            libc::ENOBUFS => ENOBUFS,
++            libc::EISCONN => EISCONN,
++            libc::ENOTCONN => ENOTCONN,
++            libc::ESHUTDOWN => ESHUTDOWN,
++            libc::ETOOMANYREFS => ETOOMANYREFS,
++            libc::ETIMEDOUT => ETIMEDOUT,
++            libc::ECONNREFUSED => ECONNREFUSED,
++            libc::ELOOP => ELOOP,
++            libc::ENAMETOOLONG => ENAMETOOLONG,
++            libc::EHOSTDOWN => EHOSTDOWN,
++            libc::EHOSTUNREACH => EHOSTUNREACH,
++            libc::ENOTEMPTY => ENOTEMPTY,
++            libc::EPROCLIM => EPROCLIM,
++            libc::EUSERS => EUSERS,
++            libc::EDQUOT => EDQUOT,
++            libc::ESTALE => ESTALE,
++            libc::EREMOTE => EREMOTE,
++            libc::EBADRPC => EBADRPC,
++            libc::ERPCMISMATCH => ERPCMISMATCH,
++            libc::EPROGUNAVAIL => EPROGUNAVAIL,
++            libc::EPROGMISMATCH => EPROGMISMATCH,
++            libc::EPROCUNAVAIL => EPROCUNAVAIL,
++            libc::ENOLCK => ENOLCK,
++            libc::ENOSYS => ENOSYS,
++            libc::EFTYPE => EFTYPE,
++            libc::EAUTH => EAUTH,
++            libc::ENEEDAUTH => ENEEDAUTH,
++            libc::EIDRM => EIDRM,
++            libc::ENOMSG => ENOMSG,
++            libc::EOVERFLOW => EOVERFLOW,
++            libc::ECANCELED => ECANCELED,
++            libc::EILSEQ => EILSEQ,
++            libc::ENOATTR => ENOATTR,
++            libc::EDOOFUS => EDOOFUS,
++            libc::EBADMSG => EBADMSG,
++            libc::EMULTIHOP => EMULTIHOP,
++            libc::ENOLINK => ENOLINK,
++            libc::EPROTO => EPROTO,
++            libc::ENOMEDIUM => ENOMEDIUM,
++            libc::EASYNC => EASYNC,
++            _   => UnknownErrno,
++        }
++    }
++}
++
++
++#[cfg(target_os = "openbsd")]
++mod consts {
++    use libc;
++
++    #[derive(Clone, Copy, Debug, Eq, PartialEq)]
++    #[repr(i32)]
++    pub enum Errno {
++        UnknownErrno    = 0,
++        EPERM           = libc::EPERM,
++        ENOENT          = libc::ENOENT,
++        ESRCH           = libc::ESRCH,
++        EINTR           = libc::EINTR,
++        EIO             = libc::EIO,
++        ENXIO           = libc::ENXIO,
++        E2BIG           = libc::E2BIG,
++        ENOEXEC         = libc::ENOEXEC,
++        EBADF           = libc::EBADF,
++        ECHILD          = libc::ECHILD,
++        EDEADLK         = libc::EDEADLK,
++        ENOMEM          = libc::ENOMEM,
++        EACCES          = libc::EACCES,
++        EFAULT          = libc::EFAULT,
++        ENOTBLK         = libc::ENOTBLK,
++        EBUSY           = libc::EBUSY,
++        EEXIST          = libc::EEXIST,
++        EXDEV           = libc::EXDEV,
++        ENODEV          = libc::ENODEV,
++        ENOTDIR         = libc::ENOTDIR,
++        EISDIR          = libc::EISDIR,
++        EINVAL          = libc::EINVAL,
++        ENFILE          = libc::ENFILE,
++        EMFILE          = libc::EMFILE,
++        ENOTTY          = libc::ENOTTY,
++        ETXTBSY         = libc::ETXTBSY,
++        EFBIG           = libc::EFBIG,
++        ENOSPC          = libc::ENOSPC,
++        ESPIPE          = libc::ESPIPE,
++        EROFS           = libc::EROFS,
++        EMLINK          = libc::EMLINK,
++        EPIPE           = libc::EPIPE,
++        EDOM            = libc::EDOM,
++        ERANGE          = libc::ERANGE,
++        EAGAIN          = libc::EAGAIN,
++        EINPROGRESS     = libc::EINPROGRESS,
++        EALREADY        = libc::EALREADY,
++        ENOTSOCK        = libc::ENOTSOCK,
++        EDESTADDRREQ    = libc::EDESTADDRREQ,
++        EMSGSIZE        = libc::EMSGSIZE,
++        EPROTOTYPE      = libc::EPROTOTYPE,
++        ENOPROTOOPT     = libc::ENOPROTOOPT,
++        EPROTONOSUPPORT = libc::EPROTONOSUPPORT,
++        ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT,
++        EOPNOTSUPP      = libc::EOPNOTSUPP,
++        EPFNOSUPPORT    = libc::EPFNOSUPPORT,
++        EAFNOSUPPORT    = libc::EAFNOSUPPORT,
++        EADDRINUSE      = libc::EADDRINUSE,
++        EADDRNOTAVAIL   = libc::EADDRNOTAVAIL,
++        ENETDOWN        = libc::ENETDOWN,
++        ENETUNREACH     = libc::ENETUNREACH,
++        ENETRESET       = libc::ENETRESET,
++        ECONNABORTED    = libc::ECONNABORTED,
++        ECONNRESET      = libc::ECONNRESET,
++        ENOBUFS         = libc::ENOBUFS,
++        EISCONN         = libc::EISCONN,
++        ENOTCONN        = libc::ENOTCONN,
++        ESHUTDOWN       = libc::ESHUTDOWN,
++        ETOOMANYREFS    = libc::ETOOMANYREFS,
++        ETIMEDOUT       = libc::ETIMEDOUT,
++        ECONNREFUSED    = libc::ECONNREFUSED,
++        ELOOP           = libc::ELOOP,
++        ENAMETOOLONG    = libc::ENAMETOOLONG,
++        EHOSTDOWN       = libc::EHOSTDOWN,
++        EHOSTUNREACH    = libc::EHOSTUNREACH,
++        ENOTEMPTY       = libc::ENOTEMPTY,
++        EPROCLIM        = libc::EPROCLIM,
++        EUSERS          = libc::EUSERS,
++        EDQUOT          = libc::EDQUOT,
++        ESTALE          = libc::ESTALE,
++        EREMOTE         = libc::EREMOTE,
++        EBADRPC         = libc::EBADRPC,
++        ERPCMISMATCH    = libc::ERPCMISMATCH,
++        EPROGUNAVAIL    = libc::EPROGUNAVAIL,
++        EPROGMISMATCH   = libc::EPROGMISMATCH,
++        EPROCUNAVAIL    = libc::EPROCUNAVAIL,
++        ENOLCK          = libc::ENOLCK,
++        ENOSYS          = libc::ENOSYS,
++        EFTYPE          = libc::EFTYPE,
++        EAUTH           = libc::EAUTH,
++        ENEEDAUTH       = libc::ENEEDAUTH,
++        EIPSEC          = libc::EIPSEC,
++        ENOATTR         = libc::ENOATTR,
++        EILSEQ          = libc::EILSEQ,
++        ENOMEDIUM       = libc::ENOMEDIUM,
++        EMEDIUMTYPE     = libc::EMEDIUMTYPE,
++        EOVERFLOW       = libc::EOVERFLOW,
++        ECANCELED       = libc::ECANCELED,
++        EIDRM           = libc::EIDRM,
++        ENOMSG          = libc::ENOMSG,
++        ENOTSUP         = libc::ENOTSUP,
++        EBADMSG         = libc::EBADMSG,
++        ENOTRECOVERABLE = libc::ENOTRECOVERABLE,
++        EOWNERDEAD      = libc::EOWNERDEAD,
++        EPROTO          = libc::EPROTO,
++    }
++
++    pub const ELAST: Errno       = Errno::ENOTSUP;
++    pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
++
++    pub const EL2NSYNC: Errno = Errno::UnknownErrno;
++
++    pub fn from_i32(e: i32) -> Errno {
++        use self::Errno::*;
++
++        match e {
++            libc::EPERM => EPERM,
++            libc::ENOENT => ENOENT,
++            libc::ESRCH => ESRCH,
++            libc::EINTR => EINTR,
++            libc::EIO => EIO,
++            libc::ENXIO => ENXIO,
++            libc::E2BIG => E2BIG,
++            libc::ENOEXEC => ENOEXEC,
++            libc::EBADF => EBADF,
++            libc::ECHILD => ECHILD,
++            libc::EDEADLK => EDEADLK,
++            libc::ENOMEM => ENOMEM,
++            libc::EACCES => EACCES,
++            libc::EFAULT => EFAULT,
++            libc::ENOTBLK => ENOTBLK,
++            libc::EBUSY => EBUSY,
++            libc::EEXIST => EEXIST,
++            libc::EXDEV => EXDEV,
++            libc::ENODEV => ENODEV,
++            libc::ENOTDIR => ENOTDIR,
++            libc::EISDIR => EISDIR,
++            libc::EINVAL => EINVAL,
++            libc::ENFILE => ENFILE,
++            libc::EMFILE => EMFILE,
++            libc::ENOTTY => ENOTTY,
++            libc::ETXTBSY => ETXTBSY,
++            libc::EFBIG => EFBIG,
++            libc::ENOSPC => ENOSPC,
++            libc::ESPIPE => ESPIPE,
++            libc::EROFS => EROFS,
++            libc::EMLINK => EMLINK,
++            libc::EPIPE => EPIPE,
++            libc::EDOM => EDOM,
++            libc::ERANGE => ERANGE,
++            libc::EAGAIN => EAGAIN,
++            libc::EINPROGRESS => EINPROGRESS,
++            libc::EALREADY => EALREADY,
++            libc::ENOTSOCK => ENOTSOCK,
++            libc::EDESTADDRREQ => EDESTADDRREQ,
++            libc::EMSGSIZE => EMSGSIZE,
++            libc::EPROTOTYPE => EPROTOTYPE,
++            libc::ENOPROTOOPT => ENOPROTOOPT,
++            libc::EPROTONOSUPPORT => EPROTONOSUPPORT,
++            libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT,
++            libc::EOPNOTSUPP => EOPNOTSUPP,
++            libc::EPFNOSUPPORT => EPFNOSUPPORT,
++            libc::EAFNOSUPPORT => EAFNOSUPPORT,
++            libc::EADDRINUSE => EADDRINUSE,
++            libc::EADDRNOTAVAIL => EADDRNOTAVAIL,
++            libc::ENETDOWN => ENETDOWN,
++            libc::ENETUNREACH => ENETUNREACH,
++            libc::ENETRESET => ENETRESET,
++            libc::ECONNABORTED => ECONNABORTED,
++            libc::ECONNRESET => ECONNRESET,
++            libc::ENOBUFS => ENOBUFS,
++            libc::EISCONN => EISCONN,
++            libc::ENOTCONN => ENOTCONN,
++            libc::ESHUTDOWN => ESHUTDOWN,
++            libc::ETOOMANYREFS => ETOOMANYREFS,
++            libc::ETIMEDOUT => ETIMEDOUT,
++            libc::ECONNREFUSED => ECONNREFUSED,
++            libc::ELOOP => ELOOP,
++            libc::ENAMETOOLONG => ENAMETOOLONG,
++            libc::EHOSTDOWN => EHOSTDOWN,
++            libc::EHOSTUNREACH => EHOSTUNREACH,
++            libc::ENOTEMPTY => ENOTEMPTY,
++            libc::EPROCLIM => EPROCLIM,
++            libc::EUSERS => EUSERS,
++            libc::EDQUOT => EDQUOT,
++            libc::ESTALE => ESTALE,
++            libc::EREMOTE => EREMOTE,
++            libc::EBADRPC => EBADRPC,
++            libc::ERPCMISMATCH => ERPCMISMATCH,
++            libc::EPROGUNAVAIL => EPROGUNAVAIL,
++            libc::EPROGMISMATCH => EPROGMISMATCH,
++            libc::EPROCUNAVAIL => EPROCUNAVAIL,
++            libc::ENOLCK => ENOLCK,
++            libc::ENOSYS => ENOSYS,
++            libc::EFTYPE => EFTYPE,
++            libc::EAUTH => EAUTH,
++            libc::ENEEDAUTH => ENEEDAUTH,
++            libc::EIPSEC => EIPSEC,
++            libc::ENOATTR => ENOATTR,
++            libc::EILSEQ => EILSEQ,
++            libc::ENOMEDIUM => ENOMEDIUM,
++            libc::EMEDIUMTYPE => EMEDIUMTYPE,
++            libc::EOVERFLOW => EOVERFLOW,
++            libc::ECANCELED => ECANCELED,
++            libc::EIDRM => EIDRM,
++            libc::ENOMSG => ENOMSG,
++            libc::ENOTSUP => ENOTSUP,
++            libc::EBADMSG => EBADMSG,
++            libc::ENOTRECOVERABLE => ENOTRECOVERABLE,
++            libc::EOWNERDEAD => EOWNERDEAD,
++            libc::EPROTO => EPROTO,
++            _   => UnknownErrno,
++        }
++    }
++}
++
++#[cfg(target_os = "netbsd")]
++mod consts {
++    use libc;
++
++    #[derive(Clone, Copy, Debug, Eq, PartialEq)]
++    #[repr(i32)]
++    pub enum Errno {
++        UnknownErrno    = 0,
++        EPERM           = libc::EPERM,
++        ENOENT          = libc::ENOENT,
++        ESRCH           = libc::ESRCH,
++        EINTR           = libc::EINTR,
++        EIO             = libc::EIO,
++        ENXIO           = libc::ENXIO,
++        E2BIG           = libc::E2BIG,
++        ENOEXEC         = libc::ENOEXEC,
++        EBADF           = libc::EBADF,
++        ECHILD          = libc::ECHILD,
++        EDEADLK         = libc::EDEADLK,
++        ENOMEM          = libc::ENOMEM,
++        EACCES          = libc::EACCES,
++        EFAULT          = libc::EFAULT,
++        ENOTBLK         = libc::ENOTBLK,
++        EBUSY           = libc::EBUSY,
++        EEXIST          = libc::EEXIST,
++        EXDEV           = libc::EXDEV,
++        ENODEV          = libc::ENODEV,
++        ENOTDIR         = libc::ENOTDIR,
++        EISDIR          = libc::EISDIR,
++        EINVAL          = libc::EINVAL,
++        ENFILE          = libc::ENFILE,
++        EMFILE          = libc::EMFILE,
++        ENOTTY          = libc::ENOTTY,
++        ETXTBSY         = libc::ETXTBSY,
++        EFBIG           = libc::EFBIG,
++        ENOSPC          = libc::ENOSPC,
++        ESPIPE          = libc::ESPIPE,
++        EROFS           = libc::EROFS,
++        EMLINK          = libc::EMLINK,
++        EPIPE           = libc::EPIPE,
++        EDOM            = libc::EDOM,
++        ERANGE          = libc::ERANGE,
++        EAGAIN          = libc::EAGAIN,
++        EINPROGRESS     = libc::EINPROGRESS,
++        EALREADY        = libc::EALREADY,
++        ENOTSOCK        = libc::ENOTSOCK,
++        EDESTADDRREQ    = libc::EDESTADDRREQ,
++        EMSGSIZE        = libc::EMSGSIZE,
++        EPROTOTYPE      = libc::EPROTOTYPE,
++        ENOPROTOOPT     = libc::ENOPROTOOPT,
++        EPROTONOSUPPORT = libc::EPROTONOSUPPORT,
++        ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT,
++        EOPNOTSUPP      = libc::EOPNOTSUPP,
++        EPFNOSUPPORT    = libc::EPFNOSUPPORT,
++        EAFNOSUPPORT    = libc::EAFNOSUPPORT,
++        EADDRINUSE      = libc::EADDRINUSE,
++        EADDRNOTAVAIL   = libc::EADDRNOTAVAIL,
++        ENETDOWN        = libc::ENETDOWN,
++        ENETUNREACH     = libc::ENETUNREACH,
++        ENETRESET       = libc::ENETRESET,
++        ECONNABORTED    = libc::ECONNABORTED,
++        ECONNRESET      = libc::ECONNRESET,
++        ENOBUFS         = libc::ENOBUFS,
++        EISCONN         = libc::EISCONN,
++        ENOTCONN        = libc::ENOTCONN,
++        ESHUTDOWN       = libc::ESHUTDOWN,
++        ETOOMANYREFS    = libc::ETOOMANYREFS,
++        ETIMEDOUT       = libc::ETIMEDOUT,
++        ECONNREFUSED    = libc::ECONNREFUSED,
++        ELOOP           = libc::ELOOP,
++        ENAMETOOLONG    = libc::ENAMETOOLONG,
++        EHOSTDOWN       = libc::EHOSTDOWN,
++        EHOSTUNREACH    = libc::EHOSTUNREACH,
++        ENOTEMPTY       = libc::ENOTEMPTY,
++        EPROCLIM        = libc::EPROCLIM,
++        EUSERS          = libc::EUSERS,
++        EDQUOT          = libc::EDQUOT,
++        ESTALE          = libc::ESTALE,
++        EREMOTE         = libc::EREMOTE,
++        EBADRPC         = libc::EBADRPC,
++        ERPCMISMATCH    = libc::ERPCMISMATCH,
++        EPROGUNAVAIL    = libc::EPROGUNAVAIL,
++        EPROGMISMATCH   = libc::EPROGMISMATCH,
++        EPROCUNAVAIL    = libc::EPROCUNAVAIL,
++        ENOLCK          = libc::ENOLCK,
++        ENOSYS          = libc::ENOSYS,
++        EFTYPE          = libc::EFTYPE,
++        EAUTH           = libc::EAUTH,
++        ENEEDAUTH       = libc::ENEEDAUTH,
++        EIDRM           = libc::EIDRM,
++        ENOMSG          = libc::ENOMSG,
++        EOVERFLOW       = libc::EOVERFLOW,
++        EILSEQ          = libc::EILSEQ,
++        ENOTSUP         = libc::ENOTSUP,
++        ECANCELED       = libc::ECANCELED,
++        EBADMSG         = libc::EBADMSG,
++        ENODATA         = libc::ENODATA,
++        ENOSR           = libc::ENOSR,
++        ENOSTR          = libc::ENOSTR,
++        ETIME           = libc::ETIME,
++        ENOATTR         = libc::ENOATTR,
++        EMULTIHOP       = libc::EMULTIHOP,
++        ENOLINK         = libc::ENOLINK,
++        EPROTO          = libc::EPROTO,
++    }
++
++    pub const ELAST: Errno       = Errno::ENOTSUP;
++    pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
++
++    pub const EL2NSYNC: Errno = Errno::UnknownErrno;
++
++    pub fn from_i32(e: i32) -> Errno {
++        use self::Errno::*;
++
++        match e {
++            libc::EPERM => EPERM,
++            libc::ENOENT => ENOENT,
++            libc::ESRCH => ESRCH,
++            libc::EINTR => EINTR,
++            libc::EIO => EIO,
++            libc::ENXIO => ENXIO,
++            libc::E2BIG => E2BIG,
++            libc::ENOEXEC => ENOEXEC,
++            libc::EBADF => EBADF,
++            libc::ECHILD => ECHILD,
++            libc::EDEADLK => EDEADLK,
++            libc::ENOMEM => ENOMEM,
++            libc::EACCES => EACCES,
++            libc::EFAULT => EFAULT,
++            libc::ENOTBLK => ENOTBLK,
++            libc::EBUSY => EBUSY,
++            libc::EEXIST => EEXIST,
++            libc::EXDEV => EXDEV,
++            libc::ENODEV => ENODEV,
++            libc::ENOTDIR => ENOTDIR,
++            libc::EISDIR => EISDIR,
++            libc::EINVAL => EINVAL,
++            libc::ENFILE => ENFILE,
++            libc::EMFILE => EMFILE,
++            libc::ENOTTY => ENOTTY,
++            libc::ETXTBSY => ETXTBSY,
++            libc::EFBIG => EFBIG,
++            libc::ENOSPC => ENOSPC,
++            libc::ESPIPE => ESPIPE,
++            libc::EROFS => EROFS,
++            libc::EMLINK => EMLINK,
++            libc::EPIPE => EPIPE,
++            libc::EDOM => EDOM,
++            libc::ERANGE => ERANGE,
++            libc::EAGAIN => EAGAIN,
++            libc::EINPROGRESS => EINPROGRESS,
++            libc::EALREADY => EALREADY,
++            libc::ENOTSOCK => ENOTSOCK,
++            libc::EDESTADDRREQ => EDESTADDRREQ,
++            libc::EMSGSIZE => EMSGSIZE,
++            libc::EPROTOTYPE => EPROTOTYPE,
++            libc::ENOPROTOOPT => ENOPROTOOPT,
++            libc::EPROTONOSUPPORT => EPROTONOSUPPORT,
++            libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT,
++            libc::EOPNOTSUPP => EOPNOTSUPP,
++            libc::EPFNOSUPPORT => EPFNOSUPPORT,
++            libc::EAFNOSUPPORT => EAFNOSUPPORT,
++            libc::EADDRINUSE => EADDRINUSE,
++            libc::EADDRNOTAVAIL => EADDRNOTAVAIL,
++            libc::ENETDOWN => ENETDOWN,
++            libc::ENETUNREACH => ENETUNREACH,
++            libc::ENETRESET => ENETRESET,
++            libc::ECONNABORTED => ECONNABORTED,
++            libc::ECONNRESET => ECONNRESET,
++            libc::ENOBUFS => ENOBUFS,
++            libc::EISCONN => EISCONN,
++            libc::ENOTCONN => ENOTCONN,
++            libc::ESHUTDOWN => ESHUTDOWN,
++            libc::ETOOMANYREFS => ETOOMANYREFS,
++            libc::ETIMEDOUT => ETIMEDOUT,
++            libc::ECONNREFUSED => ECONNREFUSED,
++            libc::ELOOP => ELOOP,
++            libc::ENAMETOOLONG => ENAMETOOLONG,
++            libc::EHOSTDOWN => EHOSTDOWN,
++            libc::EHOSTUNREACH => EHOSTUNREACH,
++            libc::ENOTEMPTY => ENOTEMPTY,
++            libc::EPROCLIM => EPROCLIM,
++            libc::EUSERS => EUSERS,
++            libc::EDQUOT => EDQUOT,
++            libc::ESTALE => ESTALE,
++            libc::EREMOTE => EREMOTE,
++            libc::EBADRPC => EBADRPC,
++            libc::ERPCMISMATCH => ERPCMISMATCH,
++            libc::EPROGUNAVAIL => EPROGUNAVAIL,
++            libc::EPROGMISMATCH => EPROGMISMATCH,
++            libc::EPROCUNAVAIL => EPROCUNAVAIL,
++            libc::ENOLCK => ENOLCK,
++            libc::ENOSYS => ENOSYS,
++            libc::EFTYPE => EFTYPE,
++            libc::EAUTH => EAUTH,
++            libc::ENEEDAUTH => ENEEDAUTH,
++            libc::EIDRM => EIDRM,
++            libc::ENOMSG => ENOMSG,
++            libc::EOVERFLOW => EOVERFLOW,
++            libc::EILSEQ => EILSEQ,
++            libc::ENOTSUP => ENOTSUP,
++            libc::ECANCELED => ECANCELED,
++            libc::EBADMSG => EBADMSG,
++            libc::ENODATA => ENODATA,
++            libc::ENOSR => ENOSR,
++            libc::ENOSTR => ENOSTR,
++            libc::ETIME => ETIME,
++            libc::ENOATTR => ENOATTR,
++            libc::EMULTIHOP => EMULTIHOP,
++            libc::ENOLINK => ENOLINK,
++            libc::EPROTO => EPROTO,
++            _   => UnknownErrno,
++        }
++    }
++}
+diff --git a/third_party/rust/nix/src/errno_dragonfly.c b/third_party/rust/nix-0.15.0/src/errno_dragonfly.c
+similarity index 100%
+rename from third_party/rust/nix/src/errno_dragonfly.c
+rename to third_party/rust/nix-0.15.0/src/errno_dragonfly.c
+diff --git a/third_party/rust/nix-0.15.0/src/fcntl.rs b/third_party/rust/nix-0.15.0/src/fcntl.rs
+new file mode 100644
+index 0000000000000..be6ee0f73a8be
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/fcntl.rs
+@@ -0,0 +1,506 @@
++use {Error, Result, NixPath};
++use errno::Errno;
++use libc::{self, c_int, c_uint, c_char, size_t, ssize_t};
++use sys::stat::Mode;
++use std::os::raw;
++use std::os::unix::io::RawFd;
++use std::ffi::OsStr;
++use std::os::unix::ffi::OsStrExt;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++use std::ptr; // For splice and copy_file_range
++#[cfg(any(target_os = "android", target_os = "linux"))]
++use sys::uio::IoVec;  // For vmsplice
++
++#[cfg(any(target_os = "linux",
++          target_os = "android",
++          target_os = "emscripten",
++          target_os = "fuchsia",
++          any(target_os = "wasi", target_env = "wasi"),
++          target_env = "uclibc",
++          target_env = "freebsd"))]
++pub use self::posix_fadvise::*;
++
++libc_bitflags!{
++    pub struct AtFlags: c_int {
++        AT_REMOVEDIR;
++        AT_SYMLINK_NOFOLLOW;
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        AT_NO_AUTOMOUNT;
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        AT_EMPTY_PATH;
++    }
++}
++
++libc_bitflags!(
++    /// Configuration options for opened files.
++    pub struct OFlag: c_int {
++        /// Mask for the access mode of the file.
++        O_ACCMODE;
++        /// Use alternate I/O semantics.
++        #[cfg(target_os = "netbsd")]
++        O_ALT_IO;
++        /// Open the file in append-only mode.
++        O_APPEND;
++        /// Generate a signal when input or output becomes possible.
++        O_ASYNC;
++        /// Closes the file descriptor once an `execve` call is made.
++        ///
++        /// Also sets the file offset to the beginning of the file.
++        O_CLOEXEC;
++        /// Create the file if it does not exist.
++        O_CREAT;
++        /// Try to minimize cache effects of the I/O for this file.
++        #[cfg(any(target_os = "android",
++                  target_os = "dragonfly",
++                  target_os = "freebsd",
++                  target_os = "linux",
++                  target_os = "netbsd"))]
++        O_DIRECT;
++        /// If the specified path isn't a directory, fail.
++        O_DIRECTORY;
++        /// Implicitly follow each `write()` with an `fdatasync()`.
++        #[cfg(any(target_os = "android",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos",
++                  target_os = "netbsd",
++                  target_os = "openbsd"))]
++        O_DSYNC;
++        /// Error out if a file was not created.
++        O_EXCL;
++        /// Open for execute only.
++        #[cfg(target_os = "freebsd")]
++        O_EXEC;
++        /// Open with an exclusive file lock.
++        #[cfg(any(target_os = "dragonfly",
++                  target_os = "freebsd",
++                  target_os = "ios",
++                  target_os = "macos",
++                  target_os = "netbsd",
++                  target_os = "openbsd"))]
++        O_EXLOCK;
++        /// Same as `O_SYNC`.
++        #[cfg(any(target_os = "dragonfly",
++                  target_os = "freebsd",
++                  target_os = "ios",
++                  all(target_os = "linux", not(target_env = "musl")),
++                  target_os = "macos",
++                  target_os = "netbsd",
++                  target_os = "openbsd"))]
++        O_FSYNC;
++        /// Allow files whose sizes can't be represented in an `off_t` to be opened.
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        O_LARGEFILE;
++        /// Do not update the file last access time during `read(2)`s.
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        O_NOATIME;
++        /// Don't attach the device as the process' controlling terminal.
++        O_NOCTTY;
++        /// Same as `O_NONBLOCK`.
++        O_NDELAY;
++        /// `open()` will fail if the given path is a symbolic link.
++        O_NOFOLLOW;
++        /// When possible, open the file in nonblocking mode.
++        O_NONBLOCK;
++        /// Don't deliver `SIGPIPE`.
++        #[cfg(target_os = "netbsd")]
++        O_NOSIGPIPE;
++        /// Obtain a file descriptor for low-level access.
++        ///
++        /// The file itself is not opened and other file operations will fail.
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        O_PATH;
++        /// Only allow reading.
++        ///
++        /// This should not be combined with `O_WRONLY` or `O_RDWR`.
++        O_RDONLY;
++        /// Allow both reading and writing.
++        ///
++        /// This should not be combined with `O_WRONLY` or `O_RDONLY`.
++        O_RDWR;
++        /// Similar to `O_DSYNC` but applies to `read`s instead.
++        #[cfg(any(target_os = "linux", target_os = "netbsd", target_os = "openbsd"))]
++        O_RSYNC;
++        /// Skip search permission checks.
++        #[cfg(target_os = "netbsd")]
++        O_SEARCH;
++        /// Open with a shared file lock.
++        #[cfg(any(target_os = "dragonfly",
++                  target_os = "freebsd",
++                  target_os = "ios",
++                  target_os = "macos",
++                  target_os = "netbsd",
++                  target_os = "openbsd"))]
++        O_SHLOCK;
++        /// Implicitly follow each `write()` with an `fsync()`.
++        O_SYNC;
++        /// Create an unnamed temporary file.
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        O_TMPFILE;
++        /// Truncate an existing regular file to 0 length if it allows writing.
++        O_TRUNC;
++        /// Restore default TTY attributes.
++        #[cfg(target_os = "freebsd")]
++        O_TTY_INIT;
++        /// Only allow writing.
++        ///
++        /// This should not be combined with `O_RDONLY` or `O_RDWR`.
++        O_WRONLY;
++    }
++);
++
++pub fn open<P: ?Sized + NixPath>(path: &P, oflag: OFlag, mode: Mode) -> Result<RawFd> {
++    let fd = path.with_nix_path(|cstr| {
++        unsafe { libc::open(cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) }
++    })?;
++
++    Errno::result(fd)
++}
++
++pub fn openat<P: ?Sized + NixPath>(dirfd: RawFd, path: &P, oflag: OFlag, mode: Mode) -> Result<RawFd> {
++    let fd = path.with_nix_path(|cstr| {
++        unsafe { libc::openat(dirfd, cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) }
++    })?;
++    Errno::result(fd)
++}
++
++pub fn renameat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(old_dirfd: Option<RawFd>, old_path: &P1,
++                                                            new_dirfd: Option<RawFd>, new_path: &P2)
++                                                            -> Result<()> {
++    let res = old_path.with_nix_path(|old_cstr| {
++        new_path.with_nix_path(|new_cstr| unsafe {
++            libc::renameat(at_rawfd(old_dirfd), old_cstr.as_ptr(),
++                           at_rawfd(new_dirfd), new_cstr.as_ptr())
++        })
++    })??;
++    Errno::result(res).map(drop)
++}
++
++fn wrap_readlink_result(buffer: &mut[u8], res: ssize_t) -> Result<&OsStr> {
++    match Errno::result(res) {
++        Err(err) => Err(err),
++        Ok(len) => {
++            if (len as usize) >= buffer.len() {
++                Err(Error::Sys(Errno::ENAMETOOLONG))
++            } else {
++                Ok(OsStr::from_bytes(&buffer[..(len as usize)]))
++            }
++        }
++    }
++}
++
++pub fn readlink<'a, P: ?Sized + NixPath>(path: &P, buffer: &'a mut [u8]) -> Result<&'a OsStr> {
++    let res = path.with_nix_path(|cstr| {
++        unsafe { libc::readlink(cstr.as_ptr(), buffer.as_mut_ptr() as *mut c_char, buffer.len() as size_t) }
++    })?;
++
++    wrap_readlink_result(buffer, res)
++}
++
++
++pub fn readlinkat<'a, P: ?Sized + NixPath>(dirfd: RawFd, path: &P, buffer: &'a mut [u8]) -> Result<&'a OsStr> {
++    let res = path.with_nix_path(|cstr| {
++        unsafe { libc::readlinkat(dirfd, cstr.as_ptr(), buffer.as_mut_ptr() as *mut c_char, buffer.len() as size_t) }
++    })?;
++
++    wrap_readlink_result(buffer, res)
++}
++
++/// Computes the raw fd consumed by a function of the form `*at`.
++pub(crate) fn at_rawfd(fd: Option<RawFd>) -> raw::c_int {
++    match fd {
++        None => libc::AT_FDCWD,
++        Some(fd) => fd,
++    }
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++libc_bitflags!(
++    /// Additional flags for file sealing, which allows for limiting operations on a file.
++    pub struct SealFlag: c_int {
++        /// Prevents further calls to `fcntl()` with `F_ADD_SEALS`.
++        F_SEAL_SEAL;
++        /// The file cannot be reduced in size.
++        F_SEAL_SHRINK;
++        /// The size of the file cannot be increased.
++        F_SEAL_GROW;
++        /// The file contents cannot be modified.
++        F_SEAL_WRITE;
++    }
++);
++
++libc_bitflags!(
++    /// Additional configuration flags for `fcntl`'s `F_SETFD`.
++    pub struct FdFlag: c_int {
++        /// The file descriptor will automatically be closed during a successful `execve(2)`.
++        FD_CLOEXEC;
++    }
++);
++
++#[derive(Debug, Eq, Hash, PartialEq)]
++pub enum FcntlArg<'a> {
++    F_DUPFD(RawFd),
++    F_DUPFD_CLOEXEC(RawFd),
++    F_GETFD,
++    F_SETFD(FdFlag), // FD_FLAGS
++    F_GETFL,
++    F_SETFL(OFlag), // O_NONBLOCK
++    F_SETLK(&'a libc::flock),
++    F_SETLKW(&'a libc::flock),
++    F_GETLK(&'a mut libc::flock),
++    #[cfg(any(target_os = "linux", target_os = "android"))]
++    F_OFD_SETLK(&'a libc::flock),
++    #[cfg(any(target_os = "linux", target_os = "android"))]
++    F_OFD_SETLKW(&'a libc::flock),
++    #[cfg(any(target_os = "linux", target_os = "android"))]
++    F_OFD_GETLK(&'a mut libc::flock),
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    F_ADD_SEALS(SealFlag),
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    F_GET_SEALS,
++    #[cfg(any(target_os = "macos", target_os = "ios"))]
++    F_FULLFSYNC,
++    #[cfg(any(target_os = "linux", target_os = "android"))]
++    F_GETPIPE_SZ,
++    #[cfg(any(target_os = "linux", target_os = "android"))]
++    F_SETPIPE_SZ(c_int),
++
++    // TODO: Rest of flags
++}
++pub use self::FcntlArg::*;
++
++// TODO: Figure out how to handle value fcntl returns
++pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int> {
++    let res = unsafe {
++        match arg {
++            F_DUPFD(rawfd) => libc::fcntl(fd, libc::F_DUPFD, rawfd),
++            F_DUPFD_CLOEXEC(rawfd) => libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, rawfd),
++            F_GETFD => libc::fcntl(fd, libc::F_GETFD),
++            F_SETFD(flag) => libc::fcntl(fd, libc::F_SETFD, flag.bits()),
++            F_GETFL => libc::fcntl(fd, libc::F_GETFL),
++            F_SETFL(flag) => libc::fcntl(fd, libc::F_SETFL, flag.bits()),
++            F_SETLK(flock) => libc::fcntl(fd, libc::F_SETLK, flock),
++            F_SETLKW(flock) => libc::fcntl(fd, libc::F_SETLKW, flock),
++            F_GETLK(flock) => libc::fcntl(fd, libc::F_GETLK, flock),
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            F_ADD_SEALS(flag) => libc::fcntl(fd, libc::F_ADD_SEALS, flag.bits()),
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            F_GET_SEALS => libc::fcntl(fd, libc::F_GET_SEALS),
++            #[cfg(any(target_os = "macos", target_os = "ios"))]
++            F_FULLFSYNC => libc::fcntl(fd, libc::F_FULLFSYNC),
++            #[cfg(any(target_os = "linux", target_os = "android"))]
++            F_GETPIPE_SZ => libc::fcntl(fd, libc::F_GETPIPE_SZ),
++            #[cfg(any(target_os = "linux", target_os = "android"))]
++            F_SETPIPE_SZ(size) => libc::fcntl(fd, libc::F_SETPIPE_SZ, size),
++            #[cfg(any(target_os = "linux", target_os = "android"))]
++            _ => unimplemented!()
++        }
++    };
++
++    Errno::result(res)
++}
++
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub enum FlockArg {
++    LockShared,
++    LockExclusive,
++    Unlock,
++    LockSharedNonblock,
++    LockExclusiveNonblock,
++    UnlockNonblock,
++}
++
++pub fn flock(fd: RawFd, arg: FlockArg) -> Result<()> {
++    use self::FlockArg::*;
++
++    let res = unsafe {
++        match arg {
++            LockShared => libc::flock(fd, libc::LOCK_SH),
++            LockExclusive => libc::flock(fd, libc::LOCK_EX),
++            Unlock => libc::flock(fd, libc::LOCK_UN),
++            LockSharedNonblock => libc::flock(fd, libc::LOCK_SH | libc::LOCK_NB),
++            LockExclusiveNonblock => libc::flock(fd, libc::LOCK_EX | libc::LOCK_NB),
++            UnlockNonblock => libc::flock(fd, libc::LOCK_UN | libc::LOCK_NB),
++        }
++    };
++
++    Errno::result(res).map(drop)
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++libc_bitflags! {
++    /// Additional flags to `splice` and friends.
++    pub struct SpliceFFlags: c_uint {
++        /// Request that pages be moved instead of copied.
++        ///
++        /// Not applicable to `vmsplice`.
++        SPLICE_F_MOVE;
++        /// Do not block on I/O.
++        SPLICE_F_NONBLOCK;
++        /// Hint that more data will be coming in a subsequent splice.
++        ///
++        /// Not applicable to `vmsplice`.
++        SPLICE_F_MORE;
++        /// Gift the user pages to the kernel.
++        ///
++        /// Not applicable to `splice`.
++        SPLICE_F_GIFT;
++    }
++}
++
++/// Copy a range of data from one file to another
++///
++/// The `copy_file_range` system call performs an in-kernel copy between
++/// file descriptors `fd_in` and `fd_out` without the additional cost of
++/// transferring data from the kernel to user space and then back into the
++/// kernel. It copies up to `len` bytes of data from file descriptor `fd_in` to
++/// file descriptor `fd_out`, overwriting any data that exists within the
++/// requested range of the target file.
++///
++/// If the `off_in` and/or `off_out` arguments are used, the values
++/// will be mutated to reflect the new position within the file after
++/// copying. If they are not used, the relevant filedescriptors will be seeked
++/// to the new position.
++///
++/// On successful completion the number of bytes actually copied will be
++/// returned.
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub fn copy_file_range(
++    fd_in: RawFd,
++    off_in: Option<&mut libc::loff_t>,
++    fd_out: RawFd,
++    off_out: Option<&mut libc::loff_t>,
++    len: usize,
++) -> Result<usize> {
++    let off_in = off_in
++        .map(|offset| offset as *mut libc::loff_t)
++        .unwrap_or(ptr::null_mut());
++    let off_out = off_out
++        .map(|offset| offset as *mut libc::loff_t)
++        .unwrap_or(ptr::null_mut());
++
++    let ret = unsafe {
++        libc::syscall(
++            libc::SYS_copy_file_range,
++            fd_in,
++            off_in,
++            fd_out,
++            off_out,
++            len,
++            0,
++        )
++    };
++    Errno::result(ret).map(|r| r as usize)
++}
++
++#[cfg(any(target_os = "linux", target_os = "android"))]
++pub fn splice(
++    fd_in: RawFd,
++    off_in: Option<&mut libc::loff_t>,
++    fd_out: RawFd,
++    off_out: Option<&mut libc::loff_t>,
++    len: usize,
++    flags: SpliceFFlags,
++) -> Result<usize> {
++    let off_in = off_in
++        .map(|offset| offset as *mut libc::loff_t)
++        .unwrap_or(ptr::null_mut());
++    let off_out = off_out
++        .map(|offset| offset as *mut libc::loff_t)
++        .unwrap_or(ptr::null_mut());
++
++    let ret = unsafe {
++        libc::splice(fd_in, off_in, fd_out, off_out, len, flags.bits())
++    };
++    Errno::result(ret).map(|r| r as usize)
++}
++
++#[cfg(any(target_os = "linux", target_os = "android"))]
++pub fn tee(fd_in: RawFd, fd_out: RawFd, len: usize, flags: SpliceFFlags) -> Result<usize> {
++    let ret = unsafe { libc::tee(fd_in, fd_out, len, flags.bits()) };
++    Errno::result(ret).map(|r| r as usize)
++}
++
++#[cfg(any(target_os = "linux", target_os = "android"))]
++pub fn vmsplice(fd: RawFd, iov: &[IoVec<&[u8]>], flags: SpliceFFlags) -> Result<usize> {
++    let ret = unsafe {
++        libc::vmsplice(fd, iov.as_ptr() as *const libc::iovec, iov.len(), flags.bits())
++    };
++    Errno::result(ret).map(|r| r as usize)
++}
++
++#[cfg(any(target_os = "linux"))]
++libc_bitflags!(
++    /// Mode argument flags for fallocate determining operation performed on a given range.
++    pub struct FallocateFlags: c_int {
++        /// File size is not changed.
++        ///
++        /// offset + len can be greater than file size.
++        FALLOC_FL_KEEP_SIZE;
++        /// Deallocates space by creating a hole.
++        ///
++        /// Must be ORed with FALLOC_FL_KEEP_SIZE. Byte range starts at offset and continues for len bytes.
++        FALLOC_FL_PUNCH_HOLE;
++        /// Removes byte range from a file without leaving a hole.
++        ///
++        /// Byte range to collapse starts at offset and continues for len bytes.
++        FALLOC_FL_COLLAPSE_RANGE;
++        /// Zeroes space in specified byte range.
++        ///
++        /// Byte range starts at offset and continues for len bytes.
++        FALLOC_FL_ZERO_RANGE;
++        /// Increases file space by inserting a hole within the file size.
++        ///
++        /// Does not overwrite existing data. Hole starts at offset and continues for len bytes.
++        FALLOC_FL_INSERT_RANGE;
++        /// Shared file data extants are made private to the file.
++        ///
++        /// Gaurantees that a subsequent write will not fail due to lack of space.
++        FALLOC_FL_UNSHARE_RANGE;
++    }
++);
++
++/// Manipulates file space.
++///
++/// Allows the caller to directly manipulate the allocated disk space for the
++/// file referred to by fd.
++#[cfg(any(target_os = "linux"))]
++pub fn fallocate(fd: RawFd, mode: FallocateFlags, offset: libc::off_t, len: libc::off_t) -> Result<c_int> {
++    let res = unsafe { libc::fallocate(fd, mode.bits(), offset, len) };
++    Errno::result(res)
++}
++
++#[cfg(any(target_os = "linux",
++          target_os = "android",
++          target_os = "emscripten",
++          target_os = "fuchsia",
++          any(target_os = "wasi", target_env = "wasi"),
++          target_env = "uclibc",
++          target_env = "freebsd"))]
++mod posix_fadvise {
++    use Result;
++    use libc;
++    use errno::Errno;
++    use std::os::unix::io::RawFd;
++
++    libc_enum! {
++        #[repr(i32)]
++        pub enum PosixFadviseAdvice {
++            POSIX_FADV_NORMAL,
++            POSIX_FADV_SEQUENTIAL,
++            POSIX_FADV_RANDOM,
++            POSIX_FADV_NOREUSE,
++            POSIX_FADV_WILLNEED,
++            POSIX_FADV_DONTNEED,
++        }
++    }
++
++    pub fn posix_fadvise(fd: RawFd,
++                         offset: libc::off_t,
++                         len: libc::off_t,
++                         advice: PosixFadviseAdvice) -> Result<libc::c_int> {
++        let res = unsafe { libc::posix_fadvise(fd, offset, len, advice as libc::c_int) };
++        Errno::result(res)
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/features.rs b/third_party/rust/nix-0.15.0/src/features.rs
+new file mode 100644
+index 0000000000000..76cdfd3a1a6f1
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/features.rs
+@@ -0,0 +1,103 @@
++//! Feature tests for OS functionality
++pub use self::os::*;
++
++#[cfg(any(target_os = "linux", target_os = "android"))]
++mod os {
++    use sys::utsname::uname;
++
++    // Features:
++    // * atomic cloexec on socket: 2.6.27
++    // * pipe2: 2.6.27
++    // * accept4: 2.6.28
++
++    static VERS_UNKNOWN: usize = 1;
++    static VERS_2_6_18:  usize = 2;
++    static VERS_2_6_27:  usize = 3;
++    static VERS_2_6_28:  usize = 4;
++    static VERS_3:       usize = 5;
++
++    #[inline]
++    fn digit(dst: &mut usize, b: u8) {
++        *dst *= 10;
++        *dst += (b - b'0') as usize;
++    }
++
++    fn parse_kernel_version() -> usize {
++        let u = uname();
++
++        let mut curr:  usize = 0;
++        let mut major: usize = 0;
++        let mut minor: usize = 0;
++        let mut patch: usize = 0;
++
++        for b in u.release().bytes() {
++            if curr >= 3 {
++                break;
++            }
++
++            match b {
++                b'.' | b'-' => {
++                    curr += 1;
++                }
++                b'0'..=b'9' => {
++                    match curr {
++                        0 => digit(&mut major, b),
++                        1 => digit(&mut minor, b),
++                        _ => digit(&mut patch, b),
++                    }
++                }
++                _ => break,
++            }
++        }
++
++        if major >= 3 {
++            VERS_3
++        } else if major >= 2 {
++            if minor >= 7 {
++                VERS_UNKNOWN
++            } else if minor >= 6 {
++                if patch >= 28 {
++                    VERS_2_6_28
++                } else if patch >= 27 {
++                    VERS_2_6_27
++                } else {
++                    VERS_2_6_18
++                }
++            } else {
++                VERS_UNKNOWN
++            }
++        } else {
++            VERS_UNKNOWN
++        }
++    }
++
++    fn kernel_version() -> usize {
++        static mut KERNEL_VERS: usize = 0;
++
++        unsafe {
++            if KERNEL_VERS == 0 {
++                KERNEL_VERS = parse_kernel_version();
++            }
++
++            KERNEL_VERS
++        }
++    }
++
++    /// Check if the OS supports atomic close-on-exec for sockets
++    pub fn socket_atomic_cloexec() -> bool {
++        kernel_version() >= VERS_2_6_27
++    }
++
++    #[test]
++    pub fn test_parsing_kernel_version() {
++        assert!(kernel_version() > 0);
++    }
++}
++
++#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly", target_os = "ios", target_os = "openbsd", target_os = "netbsd"))]
++mod os {
++    /// Check if the OS supports atomic close-on-exec for sockets
++    pub fn socket_atomic_cloexec() -> bool {
++        false
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/ifaddrs.rs b/third_party/rust/nix-0.15.0/src/ifaddrs.rs
+new file mode 100644
+index 0000000000000..12b59bcc92bef
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/ifaddrs.rs
+@@ -0,0 +1,146 @@
++//! Query network interface addresses
++//!
++//! Uses the Linux and/or BSD specific function `getifaddrs` to query the list
++//! of interfaces and their associated addresses.
++
++use std::ffi;
++use std::iter::Iterator;
++use std::mem;
++use std::option::Option;
++
++use libc;
++
++use {Result, Errno};
++use sys::socket::SockAddr;
++use net::if_::*;
++
++/// Describes a single address for an interface as returned by `getifaddrs`.
++#[derive(Clone, Debug, Eq, Hash, PartialEq)]
++pub struct InterfaceAddress {
++    /// Name of the network interface
++    pub interface_name: String,
++    /// Flags as from `SIOCGIFFLAGS` ioctl
++    pub flags: InterfaceFlags,
++    /// Network address of this interface
++    pub address: Option<SockAddr>,
++    /// Netmask of this interface
++    pub netmask: Option<SockAddr>,
++    /// Broadcast address of this interface, if applicable
++    pub broadcast: Option<SockAddr>,
++    /// Point-to-point destination address
++    pub destination: Option<SockAddr>,
++}
++
++cfg_if! {
++    if #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuchsia", target_os = "linux"))] {
++        fn get_ifu_from_sockaddr(info: &libc::ifaddrs) -> *const libc::sockaddr {
++            info.ifa_ifu
++        }
++    } else {
++        fn get_ifu_from_sockaddr(info: &libc::ifaddrs) -> *const libc::sockaddr {
++            info.ifa_dstaddr
++        }
++    }
++}
++
++impl InterfaceAddress {
++    /// Create an `InterfaceAddress` from the libc struct.
++    fn from_libc_ifaddrs(info: &libc::ifaddrs) -> InterfaceAddress {
++        let ifname = unsafe { ffi::CStr::from_ptr(info.ifa_name) };
++        let address = unsafe { SockAddr::from_libc_sockaddr(info.ifa_addr) };
++        let netmask = unsafe { SockAddr::from_libc_sockaddr(info.ifa_netmask) };
++        let mut addr = InterfaceAddress {
++            interface_name: ifname.to_string_lossy().to_string(),
++            flags: InterfaceFlags::from_bits_truncate(info.ifa_flags as i32),
++            address: address,
++            netmask: netmask,
++            broadcast: None,
++            destination: None,
++        };
++
++        let ifu = get_ifu_from_sockaddr(info);
++        if addr.flags.contains(InterfaceFlags::IFF_POINTOPOINT) {
++            addr.destination = unsafe { SockAddr::from_libc_sockaddr(ifu) };
++        } else if addr.flags.contains(InterfaceFlags::IFF_BROADCAST) {
++            addr.broadcast = unsafe { SockAddr::from_libc_sockaddr(ifu) };
++        }
++
++        addr
++    }
++}
++
++/// Holds the results of `getifaddrs`.
++///
++/// Use the function `getifaddrs` to create this Iterator. Note that the
++/// actual list of interfaces can be iterated once and will be freed as
++/// soon as the Iterator goes out of scope.
++#[derive(Debug, Eq, Hash, PartialEq)]
++pub struct InterfaceAddressIterator {
++    base: *mut libc::ifaddrs,
++    next: *mut libc::ifaddrs,
++}
++
++impl Drop for InterfaceAddressIterator {
++    fn drop(&mut self) {
++        unsafe { libc::freeifaddrs(self.base) };
++    }
++}
++
++impl Iterator for InterfaceAddressIterator {
++    type Item = InterfaceAddress;
++    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
++        match unsafe { self.next.as_ref() } {
++            Some(ifaddr) => {
++                self.next = ifaddr.ifa_next;
++                Some(InterfaceAddress::from_libc_ifaddrs(ifaddr))
++            }
++            None => None,
++        }
++    }
++}
++
++/// Get interface addresses using libc's `getifaddrs`
++///
++/// Note that the underlying implementation differs between OSes. Only the
++/// most common address families are supported by the nix crate (due to
++/// lack of time and complexity of testing). The address family is encoded
++/// in the specific variant of `SockAddr` returned for the fields `address`,
++/// `netmask`, `broadcast`, and `destination`. For any entry not supported,
++/// the returned list will contain a `None` entry.
++///
++/// # Example
++/// ```
++/// let addrs = nix::ifaddrs::getifaddrs().unwrap();
++/// for ifaddr in addrs {
++///   match ifaddr.address {
++///     Some(address) => {
++///       println!("interface {} address {}",
++///                ifaddr.interface_name, address);
++///     },
++///     None => {
++///       println!("interface {} with unsupported address family",
++///                ifaddr.interface_name);
++///     }
++///   }
++/// }
++/// ```
++pub fn getifaddrs() -> Result<InterfaceAddressIterator> {
++    let mut addrs: *mut libc::ifaddrs = unsafe { mem::uninitialized() };
++    Errno::result(unsafe { libc::getifaddrs(&mut addrs) }).map(|_| {
++        InterfaceAddressIterator {
++            base: addrs,
++            next: addrs,
++        }
++    })
++}
++
++#[cfg(test)]
++mod tests {
++    use super::*;
++
++    // Only checks if `getifaddrs` can be invoked without panicking.
++    #[test]
++    fn test_getifaddrs() {
++        let _ = getifaddrs();
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/kmod.rs b/third_party/rust/nix-0.15.0/src/kmod.rs
+new file mode 100644
+index 0000000000000..e853261b14f9d
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/kmod.rs
+@@ -0,0 +1,123 @@
++//! Load and unload kernel modules.
++//!
++//! For more details see
++
++use libc;
++use std::ffi::CStr;
++use std::os::unix::io::AsRawFd;
++
++use errno::Errno;
++use Result;
++
++/// Loads a kernel module from a buffer.
++///
++/// It loads an ELF image into kernel space,
++/// performs any necessary symbol relocations,
++/// initializes module parameters to values provided by the caller,
++/// and then runs the module's init function.
++///
++/// This function requires `CAP_SYS_MODULE` privilege.
++///
++/// The `module_image` argument points to a buffer containing the binary image
++/// to be loaded. The buffer should contain a valid ELF image
++/// built for the running kernel.
++///
++/// The `param_values` argument is a string containing space-delimited specifications
++/// of the values for module parameters.
++/// Each of the parameter specifications has the form:
++///
++/// `name[=value[,value...]]`
++///
++/// # Example
++///
++/// ```no_run
++/// use std::fs::File;
++/// use std::io::Read;
++/// use std::ffi::CString;
++/// use nix::kmod::init_module;
++///
++/// let mut f = File::open("mykernel.ko").unwrap();
++/// let mut contents: Vec<u8> = Vec::new();
++/// f.read_to_end(&mut contents).unwrap();
++/// init_module(&mut contents, &CString::new("who=Rust when=Now,12").unwrap()).unwrap();
++/// ```
++///
++/// See [`man init_module(2)`](http://man7.org/linux/man-pages/man2/init_module.2.html) for more information.
++pub fn init_module(module_image: &[u8], param_values: &CStr) -> Result<()> {
++    let res = unsafe {
++        libc::syscall(
++            libc::SYS_init_module,
++            module_image.as_ptr(),
++            module_image.len(),
++            param_values.as_ptr(),
++        )
++    };
++
++    Errno::result(res).map(drop)
++}
++
++libc_bitflags!(
++    /// Flags used by the `finit_module` function.
++    pub struct ModuleInitFlags: libc::c_uint {
++        /// Ignore symbol version hashes.
++        MODULE_INIT_IGNORE_MODVERSIONS;
++        /// Ignore kernel version magic.
++        MODULE_INIT_IGNORE_VERMAGIC;
++    }
++);
++
++/// Loads a kernel module from a given file descriptor.
++///
++/// # Example
++///
++/// ```no_run
++/// use std::fs::File;
++/// use std::ffi::CString;
++/// use nix::kmod::{finit_module, ModuleInitFlags};
++///
++/// let f = File::open("mymod.ko").unwrap();
++/// finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty()).unwrap();
++/// ```
++///
++/// See [`man init_module(2)`](http://man7.org/linux/man-pages/man2/init_module.2.html) for more information.
++pub fn finit_module<T: AsRawFd>(fd: &T, param_values: &CStr, flags: ModuleInitFlags) -> Result<()> {
++    let res = unsafe {
++        libc::syscall(
++            libc::SYS_finit_module,
++            fd.as_raw_fd(),
++            param_values.as_ptr(),
++            flags.bits(),
++        )
++    };
++
++    Errno::result(res).map(drop)
++}
++
++libc_bitflags!(
++    /// Flags used by `delete_module`.
++    ///
++    /// See [`man delete_module(2)`](http://man7.org/linux/man-pages/man2/delete_module.2.html)
++    /// for a detailed description how these flags work.
++    pub struct DeleteModuleFlags: libc::c_int {
++        O_NONBLOCK;
++        O_TRUNC;
++    }
++);
++
++/// Unloads the kernel module with the given name.
++///
++/// # Example
++///
++/// ```no_run
++/// use std::ffi::CString;
++/// use nix::kmod::{delete_module, DeleteModuleFlags};
++///
++/// delete_module(&CString::new("mymod").unwrap(), DeleteModuleFlags::O_NONBLOCK).unwrap();
++/// ```
++///
++/// See [`man delete_module(2)`](http://man7.org/linux/man-pages/man2/delete_module.2.html) for more information.
++pub fn delete_module(name: &CStr, flags: DeleteModuleFlags) -> Result<()> {
++    let res = unsafe { libc::syscall(libc::SYS_delete_module, name.as_ptr(), flags.bits()) };
++
++    Errno::result(res).map(drop)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/lib.rs b/third_party/rust/nix-0.15.0/src/lib.rs
+new file mode 100644
+index 0000000000000..71485d2af1824
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/lib.rs
+@@ -0,0 +1,284 @@
++//! Rust friendly bindings to the various *nix system functions.
++//!
++//! Modules are structured according to the C header file that they would be
++//! defined in.
++#![crate_name = "nix"]
++#![cfg(unix)]
++#![allow(non_camel_case_types)]
++// latest bitflags triggers a rustc bug with cross-crate macro expansions causing dead_code
++// warnings even though the macro expands into something with allow(dead_code)
++#![allow(dead_code)]
++#![cfg_attr(test, deny(warnings))]
++#![recursion_limit = "500"]
++#![deny(unused)]
++#![deny(unstable_features)]
++#![deny(missing_copy_implementations)]
++#![deny(missing_debug_implementations)]
++// XXX Allow deprecated items until release 0.16.0.  See issue #1096.
++#![allow(deprecated)]
++
++// External crates
++#[macro_use]
++extern crate bitflags;
++#[macro_use]
++extern crate cfg_if;
++extern crate void;
++
++// Re-exported external crates
++pub extern crate libc;
++
++// Private internal modules
++#[macro_use] mod macros;
++
++// Public crates
++pub mod dir;
++pub mod errno;
++#[deny(missing_docs)]
++pub mod features;
++pub mod fcntl;
++#[deny(missing_docs)]
++#[cfg(any(target_os = "android",
++          target_os = "dragonfly",
++          target_os = "freebsd",
++          target_os = "ios",
++          target_os = "linux",
++          target_os = "macos",
++          target_os = "netbsd",
++          target_os = "openbsd"))]
++pub mod ifaddrs;
++#[cfg(any(target_os = "android",
++          target_os = "linux"))]
++pub mod kmod;
++#[cfg(any(target_os = "android",
++          target_os = "linux"))]
++pub mod mount;
++#[cfg(any(target_os = "dragonfly",
++          target_os = "freebsd",
++          target_os = "fushsia",
++          target_os = "linux",
++          target_os = "netbsd"))]
++pub mod mqueue;
++#[deny(missing_docs)]
++pub mod net;
++#[deny(missing_docs)]
++pub mod poll;
++#[deny(missing_docs)]
++pub mod pty;
++pub mod sched;
++pub mod sys;
++// This can be implemented for other platforms as soon as libc
++// provides bindings for them.
++#[cfg(all(target_os = "linux",
++          any(target_arch = "x86", target_arch = "x86_64")))]
++pub mod ucontext;
++pub mod unistd;
++
++/*
++ *
++ * ===== Result / Error =====
++ *
++ */
++
++use libc::{c_char, PATH_MAX};
++
++use std::{error, fmt, ptr, result};
++use std::ffi::{CStr, OsStr};
++use std::os::unix::ffi::OsStrExt;
++use std::path::{Path, PathBuf};
++
++use errno::Errno;
++
++/// Nix Result Type
++pub type Result<T> = result::Result<T, Error>;
++
++/// Nix Error Type
++///
++/// The nix error type provides a common way of dealing with
++/// various system system/libc calls that might fail.  Each
++/// error has a corresponding errno (usually the one from the
++/// underlying OS) to which it can be mapped in addition to
++/// implementing other common traits.
++#[derive(Clone, Copy, Debug, Eq, PartialEq)]
++pub enum Error {
++    Sys(Errno),
++    InvalidPath,
++    /// The operation involved a conversion to Rust's native String type, which failed because the
++    /// string did not contain all valid UTF-8.
++    InvalidUtf8,
++    /// The operation is not supported by Nix, in this instance either use the libc bindings or
++    /// consult the module documentation to see if there is a more appropriate interface available.
++    UnsupportedOperation,
++}
++
++impl Error {
++    /// Convert this `Error` to an [`Errno`](enum.Errno.html).
++    ///
++    /// # Example
++    ///
++    /// ```
++    /// # use nix::Error;
++    /// # use nix::errno::Errno;
++    /// let e = Error::from(Errno::EPERM);
++    /// assert_eq!(Some(Errno::EPERM), e.as_errno());
++    /// ```
++    pub fn as_errno(&self) -> Option<Errno> {
++        if let &Error::Sys(ref e) = self {
++            Some(*e)
++        } else {
++            None
++        }
++    }
++
++    /// Create a nix Error from a given errno
++    pub fn from_errno(errno: Errno) -> Error {
++        Error::Sys(errno)
++    }
++
++    /// Get the current errno and convert it to a nix Error
++    pub fn last() -> Error {
++        Error::Sys(Errno::last())
++    }
++
++    /// Create a new invalid argument error (`EINVAL`)
++    pub fn invalid_argument() -> Error {
++        Error::Sys(Errno::EINVAL)
++    }
++
++}
++
++impl From<Errno> for Error {
++    fn from(errno: Errno) -> Error { Error::from_errno(errno) }
++}
++
++impl From<std::string::FromUtf8Error> for Error {
++    fn from(_: std::string::FromUtf8Error) -> Error { Error::InvalidUtf8 }
++}
++
++impl error::Error for Error {
++    fn description(&self) -> &str {
++        match *self {
++            Error::InvalidPath => "Invalid path",
++            Error::InvalidUtf8 => "Invalid UTF-8 string",
++            Error::UnsupportedOperation => "Unsupported Operation",
++            Error::Sys(ref errno) => errno.desc(),
++        }
++    }
++}
++
++impl fmt::Display for Error {
++    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++        match *self {
++            Error::InvalidPath => write!(f, "Invalid path"),
++            Error::InvalidUtf8 => write!(f, "Invalid UTF-8 string"),
++            Error::UnsupportedOperation => write!(f, "Unsupported Operation"),
++            Error::Sys(errno) => write!(f, "{:?}: {}", errno, errno.desc()),
++        }
++    }
++}
++
++pub trait NixPath {
++    fn len(&self) -> usize;
++
++    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
++        where F: FnOnce(&CStr) -> T;
++}
++
++impl NixPath for str {
++    fn len(&self) -> usize {
++        NixPath::len(OsStr::new(self))
++    }
++
++    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
++        where F: FnOnce(&CStr) -> T {
++            OsStr::new(self).with_nix_path(f)
++        }
++}
++
++impl NixPath for OsStr {
++    fn len(&self) -> usize {
++        self.as_bytes().len()
++    }
++
++    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
++        where F: FnOnce(&CStr) -> T {
++            self.as_bytes().with_nix_path(f)
++        }
++}
++
++impl NixPath for CStr {
++    fn len(&self) -> usize {
++        self.to_bytes().len()
++    }
++
++    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
++            where F: FnOnce(&CStr) -> T {
++        // Equivalence with the [u8] impl.
++        if self.len() >= PATH_MAX as usize {
++            return Err(Error::InvalidPath);
++        }
++
++        Ok(f(self))
++    }
++}
++
++impl NixPath for [u8] {
++    fn len(&self) -> usize {
++        self.len()
++    }
++
++    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
++            where F: FnOnce(&CStr) -> T {
++        let mut buf = [0u8; PATH_MAX as usize];
++
++        if self.len() >= PATH_MAX as usize {
++            return Err(Error::InvalidPath);
++        }
++
++        match self.iter().position(|b| *b == 0) {
++            Some(_) => Err(Error::InvalidPath),
++            None => {
++                unsafe {
++                    // TODO: Replace with bytes::copy_memory. rust-lang/rust#24028
++                    ptr::copy_nonoverlapping(self.as_ptr(), buf.as_mut_ptr(), self.len());
++                    Ok(f(CStr::from_ptr(buf.as_ptr() as *const c_char)))
++                }
++
++            }
++        }
++    }
++}
++
++impl NixPath for Path {
++    fn len(&self) -> usize {
++        NixPath::len(self.as_os_str())
++    }
++
++    fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
++        self.as_os_str().with_nix_path(f)
++    }
++}
++
++impl NixPath for PathBuf {
++    fn len(&self) -> usize {
++        NixPath::len(self.as_os_str())
++    }
++
++    fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
++        self.as_os_str().with_nix_path(f)
++    }
++}
++
++/// Treats `None` as an empty string.
++impl<'a, NP: ?Sized + NixPath>  NixPath for Option<&'a NP> {
++    fn len(&self) -> usize {
++        self.map_or(0, NixPath::len)
++    }
++
++    fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
++        if let Some(nix_path) = *self {
++            nix_path.with_nix_path(f)
++        } else {
++            unsafe { CStr::from_ptr("\0".as_ptr() as *const _).with_nix_path(f) }
++        }
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/macros.rs b/third_party/rust/nix-0.15.0/src/macros.rs
+new file mode 100644
+index 0000000000000..3d1b0e4b7699c
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/macros.rs
+@@ -0,0 +1,264 @@
++/// The `libc_bitflags!` macro helps with a common use case of defining a public bitflags type
++/// with values from the libc crate. It is used the same way as the `bitflags!` macro, except
++/// that only the name of the flag value has to be given.
++///
++/// The `libc` crate must be in scope with the name `libc`.
++///
++/// # Example
++/// ```
++/// libc_bitflags!{
++///     pub struct ProtFlags: libc::c_int {
++///         PROT_NONE;
++///         PROT_READ;
++///         /// PROT_WRITE enables write protect
++///         PROT_WRITE;
++///         PROT_EXEC;
++///         #[cfg(any(target_os = "linux", target_os = "android"))]
++///         PROT_GROWSDOWN;
++///         #[cfg(any(target_os = "linux", target_os = "android"))]
++///         PROT_GROWSUP;
++///     }
++/// }
++/// ```
++///
++/// Example with casting, due to a mistake in libc. In this example, the
++/// various flags have different types, so we cast the broken ones to the right
++/// type.
++///
++/// ```
++/// libc_bitflags!{
++///     pub struct SaFlags: libc::c_ulong {
++///         SA_NOCLDSTOP as libc::c_ulong;
++///         SA_NOCLDWAIT;
++///         SA_NODEFER as libc::c_ulong;
++///         SA_ONSTACK;
++///         SA_RESETHAND as libc::c_ulong;
++///         SA_RESTART as libc::c_ulong;
++///         SA_SIGINFO;
++///     }
++/// }
++/// ```
++macro_rules! libc_bitflags {
++    (
++        $(#[$outer:meta])*
++        pub struct $BitFlags:ident: $T:ty {
++            $(
++                $(#[$inner:ident $($args:tt)*])*
++                $Flag:ident $(as $cast:ty)*;
++            )+
++        }
++    ) => {
++        bitflags! {
++            $(#[$outer])*
++            pub struct $BitFlags: $T {
++                $(
++                    $(#[$inner $($args)*])*
++                    const $Flag = libc::$Flag $(as $cast)*;
++                )+
++            }
++        }
++    };
++}
++
++/// The `libc_enum!` macro helps with a common use case of defining an enum exclusively using
++/// values from the `libc` crate. This macro supports both `pub` and private `enum`s.
++///
++/// The `libc` crate must be in scope with the name `libc`.
++///
++/// # Example
++/// ```
++/// libc_enum!{
++///     pub enum ProtFlags {
++///         PROT_NONE,
++///         PROT_READ,
++///         PROT_WRITE,
++///         PROT_EXEC,
++///         #[cfg(any(target_os = "linux", target_os = "android"))]
++///         PROT_GROWSDOWN,
++///         #[cfg(any(target_os = "linux", target_os = "android"))]
++///         PROT_GROWSUP,
++///     }
++/// }
++/// ```
++macro_rules! libc_enum {
++    // (non-pub) Exit rule.
++    (@make_enum
++        {
++            name: $BitFlags:ident,
++            attrs: [$($attrs:tt)*],
++            entries: [$($entries:tt)*],
++        }
++    ) => {
++        $($attrs)*
++        #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
++        enum $BitFlags {
++            $($entries)*
++        }
++    };
++
++    // (pub) Exit rule.
++    (@make_enum
++        {
++            pub,
++            name: $BitFlags:ident,
++            attrs: [$($attrs:tt)*],
++            entries: [$($entries:tt)*],
++        }
++    ) => {
++        $($attrs)*
++        #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
++        pub enum $BitFlags {
++            $($entries)*
++        }
++    };
++
++    // (non-pub) Done accumulating.
++    (@accumulate_entries
++        {
++            name: $BitFlags:ident,
++            attrs: $attrs:tt,
++        },
++        $entries:tt;
++    ) => {
++        libc_enum! {
++            @make_enum
++            {
++                name: $BitFlags,
++                attrs: $attrs,
++                entries: $entries,
++            }
++        }
++    };
++
++    // (pub) Done accumulating.
++    (@accumulate_entries
++        {
++            pub,
++            name: $BitFlags:ident,
++            attrs: $attrs:tt,
++        },
++        $entries:tt;
++    ) => {
++        libc_enum! {
++            @make_enum
++            {
++                pub,
++                name: $BitFlags,
++                attrs: $attrs,
++                entries: $entries,
++            }
++        }
++    };
++
++    // Munch an attr.
++    (@accumulate_entries
++        $prefix:tt,
++        [$($entries:tt)*];
++        #[$attr:meta] $($tail:tt)*
++    ) => {
++        libc_enum! {
++            @accumulate_entries
++            $prefix,
++            [
++                $($entries)*
++                #[$attr]
++            ];
++            $($tail)*
++        }
++    };
++
++    // Munch last ident if not followed by a comma.
++    (@accumulate_entries
++        $prefix:tt,
++        [$($entries:tt)*];
++        $entry:ident
++    ) => {
++        libc_enum! {
++            @accumulate_entries
++            $prefix,
++            [
++                $($entries)*
++                $entry = libc::$entry,
++            ];
++        }
++    };
++
++    // Munch an ident; covers terminating comma case.
++    (@accumulate_entries
++        $prefix:tt,
++        [$($entries:tt)*];
++        $entry:ident, $($tail:tt)*
++    ) => {
++        libc_enum! {
++            @accumulate_entries
++            $prefix,
++            [
++                $($entries)*
++                $entry = libc::$entry,
++            ];
++            $($tail)*
++        }
++    };
++
++    // Munch an ident and cast it to the given type; covers terminating comma.
++    (@accumulate_entries
++        $prefix:tt,
++        [$($entries:tt)*];
++        $entry:ident as $ty:ty, $($tail:tt)*
++    ) => {
++        libc_enum! {
++            @accumulate_entries
++            $prefix,
++            [
++                $($entries)*
++                $entry = libc::$entry as $ty,
++            ];
++            $($tail)*
++        }
++    };
++
++    // (non-pub) Entry rule.
++    (
++        $(#[$attr:meta])*
++        enum $BitFlags:ident {
++            $($vals:tt)*
++        }
++    ) => {
++        libc_enum! {
++            @accumulate_entries
++            {
++                name: $BitFlags,
++                attrs: [$(#[$attr])*],
++            },
++            [];
++            $($vals)*
++        }
++    };
++
++    // (pub) Entry rule.
++    (
++        $(#[$attr:meta])*
++        pub enum $BitFlags:ident {
++            $($vals:tt)*
++        }
++    ) => {
++        libc_enum! {
++            @accumulate_entries
++            {
++                pub,
++                name: $BitFlags,
++                attrs: [$(#[$attr])*],
++            },
++            [];
++            $($vals)*
++        }
++    };
++}
++
++/// A Rust version of the familiar C `offset_of` macro.  It returns the byte
++/// offset of `field` within struct `ty`
++macro_rules! offset_of {
++    ($ty:ty, $field:ident) => {
++        &(*(0 as *const $ty)).$field as *const _ as usize
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/mount.rs b/third_party/rust/nix-0.15.0/src/mount.rs
+new file mode 100644
+index 0000000000000..a9902b170ace8
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/mount.rs
+@@ -0,0 +1,98 @@
++use libc::{self, c_ulong, c_int};
++use {Result, NixPath};
++use errno::Errno;
++
++libc_bitflags!(
++    pub struct MsFlags: c_ulong {
++        /// Mount read-only
++        MS_RDONLY;
++        /// Ignore suid and sgid bits
++        MS_NOSUID;
++        /// Disallow access to device special files
++        MS_NODEV;
++        /// Disallow program execution
++        MS_NOEXEC;
++        /// Writes are synced at once
++        MS_SYNCHRONOUS;
++        /// Alter flags of a mounted FS
++        MS_REMOUNT;
++        /// Allow mandatory locks on a FS
++        MS_MANDLOCK;
++        /// Directory modifications are synchronous
++        MS_DIRSYNC;
++        /// Do not update access times
++        MS_NOATIME;
++        /// Do not update directory access times
++        MS_NODIRATIME;
++        /// Linux 2.4.0 - Bind directory at different place
++        MS_BIND;
++        MS_MOVE;
++        MS_REC;
++        MS_SILENT;
++        MS_POSIXACL;
++        MS_UNBINDABLE;
++        MS_PRIVATE;
++        MS_SLAVE;
++        MS_SHARED;
++        MS_RELATIME;
++        MS_KERNMOUNT;
++        MS_I_VERSION;
++        MS_STRICTATIME;
++        MS_ACTIVE;
++        MS_NOUSER;
++        MS_RMT_MASK;
++        MS_MGC_VAL;
++        MS_MGC_MSK;
++    }
++);
++
++libc_bitflags!(
++    pub struct MntFlags: c_int {
++        MNT_FORCE;
++        MNT_DETACH;
++        MNT_EXPIRE;
++    }
++);
++
++pub fn mount<P1: ?Sized + NixPath, P2: ?Sized + NixPath, P3: ?Sized + NixPath, P4: ?Sized + NixPath>(
++        source: Option<&P1>,
++        target: &P2,
++        fstype: Option<&P3>,
++        flags: MsFlags,
++        data: Option<&P4>) -> Result<()> {
++
++    let res =
++        source.with_nix_path(|source| {
++            target.with_nix_path(|target| {
++                fstype.with_nix_path(|fstype| {
++                    data.with_nix_path(|data| {
++                        unsafe {
++                            libc::mount(source.as_ptr(),
++                                       target.as_ptr(),
++                                       fstype.as_ptr(),
++                                       flags.bits,
++                                       data.as_ptr() as *const libc::c_void)
++                        }
++                    })
++                })
++            })
++        })????;
++
++    Errno::result(res).map(drop)
++}
++
++pub fn umount<P: ?Sized + NixPath>(target: &P) -> Result<()> {
++    let res = target.with_nix_path(|cstr| {
++        unsafe { libc::umount(cstr.as_ptr()) }
++    })?;
++
++    Errno::result(res).map(drop)
++}
++
++pub fn umount2<P: ?Sized + NixPath>(target: &P, flags: MntFlags) -> Result<()> {
++    let res = target.with_nix_path(|cstr| {
++        unsafe { libc::umount2(cstr.as_ptr(), flags.bits) }
++    })?;
++
++    Errno::result(res).map(drop)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/mqueue.rs b/third_party/rust/nix-0.15.0/src/mqueue.rs
+new file mode 100644
+index 0000000000000..b958b71cddb46
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/mqueue.rs
+@@ -0,0 +1,162 @@
++//! Posix Message Queue functions
++//!
++//! [Further reading and details on the C API](http://man7.org/linux/man-pages/man7/mq_overview.7.html)
++
++use Result;
++use errno::Errno;
++
++use libc::{self, c_char, c_long, mqd_t, size_t};
++use std::ffi::CString;
++use sys::stat::Mode;
++use std::mem;
++
++libc_bitflags!{
++    pub struct MQ_OFlag: libc::c_int {
++        O_RDONLY;
++        O_WRONLY;
++        O_RDWR;
++        O_CREAT;
++        O_EXCL;
++        O_NONBLOCK;
++        O_CLOEXEC;
++    }
++}
++
++libc_bitflags!{
++    pub struct FdFlag: libc::c_int {
++        FD_CLOEXEC;
++    }
++}
++
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct MqAttr {
++    mq_attr: libc::mq_attr,
++}
++
++impl MqAttr {
++    pub fn new(mq_flags: c_long,
++               mq_maxmsg: c_long,
++               mq_msgsize: c_long,
++               mq_curmsgs: c_long)
++               -> MqAttr {
++        let mut attr = unsafe { mem::uninitialized::<libc::mq_attr>() };
++        attr.mq_flags = mq_flags;
++        attr.mq_maxmsg = mq_maxmsg;
++        attr.mq_msgsize = mq_msgsize;
++        attr.mq_curmsgs = mq_curmsgs;
++        MqAttr { mq_attr: attr }
++    }
++
++    pub fn flags(&self) -> c_long {
++        self.mq_attr.mq_flags
++    }
++}
++
++
++/// Open a message queue
++///
++/// See also [`mq_open(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_open.html)
++pub fn mq_open(name: &CString,
++               oflag: MQ_OFlag,
++               mode: Mode,
++               attr: Option<&MqAttr>)
++               -> Result<mqd_t> {
++    let res = match attr {
++        Some(mq_attr) => unsafe {
++            libc::mq_open(name.as_ptr(),
++                          oflag.bits(),
++                          mode.bits() as libc::c_int,
++                          &mq_attr.mq_attr as *const libc::mq_attr)
++        },
++        None => unsafe { libc::mq_open(name.as_ptr(), oflag.bits()) },
++    };
++    Errno::result(res)
++}
++
++/// Remove a message queue
++///
++/// See also [`mq_unlink(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_unlink.html)
++pub fn mq_unlink(name: &CString) -> Result<()> {
++    let res = unsafe { libc::mq_unlink(name.as_ptr()) };
++    Errno::result(res).map(drop)
++}
++
++/// Close a message queue
++///
++/// See also [`mq_close(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_close.html)
++pub fn mq_close(mqdes: mqd_t) -> Result<()> {
++    let res = unsafe { libc::mq_close(mqdes) };
++    Errno::result(res).map(drop)
++}
++
++/// Receive a message from a message queue
++///
++/// See also [`mq_receive(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_receive.html)
++pub fn mq_receive(mqdes: mqd_t, message: &mut [u8], msg_prio: &mut u32) -> Result<usize> {
++    let len = message.len() as size_t;
++    let res = unsafe {
++        libc::mq_receive(mqdes,
++                         message.as_mut_ptr() as *mut c_char,
++                         len,
++                         msg_prio as *mut u32)
++    };
++    Errno::result(res).map(|r| r as usize)
++}
++
++/// Send a message to a message queue
++///
++/// See also [`mq_send(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html)
++pub fn mq_send(mqdes: mqd_t, message: &[u8], msq_prio: u32) -> Result<()> {
++    let res = unsafe {
++        libc::mq_send(mqdes,
++                      message.as_ptr() as *const c_char,
++                      message.len(),
++                      msq_prio)
++    };
++    Errno::result(res).map(drop)
++}
++
++/// Get message queue attributes
++///
++/// See also [`mq_getattr(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_getattr.html)
++pub fn mq_getattr(mqd: mqd_t) -> Result<MqAttr> {
++    let mut attr = unsafe { mem::uninitialized::<libc::mq_attr>() };
++    let res = unsafe { libc::mq_getattr(mqd, &mut attr) };
++    Errno::result(res).map(|_| MqAttr { mq_attr: attr })
++}
++
++/// Set the attributes of the message queue. Only `O_NONBLOCK` can be set, everything else will be ignored
++/// Returns the old attributes
++/// It is recommend to use the `mq_set_nonblock()` and `mq_remove_nonblock()` convenience functions as they are easier to use
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_setattr.html)
++pub fn mq_setattr(mqd: mqd_t, newattr: &MqAttr) -> Result<MqAttr> {
++    let mut attr = unsafe { mem::uninitialized::<libc::mq_attr>() };
++    let res = unsafe { libc::mq_setattr(mqd, &newattr.mq_attr as *const libc::mq_attr, &mut attr) };
++    Errno::result(res).map(|_| MqAttr { mq_attr: attr })
++}
++
++/// Convenience function.
++/// Sets the `O_NONBLOCK` attribute for a given message queue descriptor
++/// Returns the old attributes
++pub fn mq_set_nonblock(mqd: mqd_t) -> Result<(MqAttr)> {
++    let oldattr = mq_getattr(mqd)?;
++    let newattr = MqAttr::new(MQ_OFlag::O_NONBLOCK.bits() as c_long,
++                              oldattr.mq_attr.mq_maxmsg,
++                              oldattr.mq_attr.mq_msgsize,
++                              oldattr.mq_attr.mq_curmsgs);
++    mq_setattr(mqd, &newattr)
++}
++
++/// Convenience function.
++/// Removes `O_NONBLOCK` attribute for a given message queue descriptor
++/// Returns the old attributes
++pub fn mq_remove_nonblock(mqd: mqd_t) -> Result<(MqAttr)> {
++    let oldattr = mq_getattr(mqd)?;
++    let newattr = MqAttr::new(0,
++                              oldattr.mq_attr.mq_maxmsg,
++                              oldattr.mq_attr.mq_msgsize,
++                              oldattr.mq_attr.mq_curmsgs);
++    mq_setattr(mqd, &newattr)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/net/if_.rs b/third_party/rust/nix-0.15.0/src/net/if_.rs
+new file mode 100644
+index 0000000000000..58d677ae343d1
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/net/if_.rs
+@@ -0,0 +1,268 @@
++//! Network interface name resolution.
++//!
++//! Uses Linux and/or POSIX functions to resolve interface names like "eth0"
++//! or "socan1" into device numbers.
++
++use libc;
++use libc::c_uint;
++use {Result, Error, NixPath};
++
++/// Resolve an interface into a interface number.
++pub fn if_nametoindex<P: ?Sized + NixPath>(name: &P) -> Result<c_uint> {
++    let if_index = name.with_nix_path(|name| unsafe { libc::if_nametoindex(name.as_ptr()) })?;
++
++    if if_index == 0 {
++        Err(Error::last())
++    } else {
++        Ok(if_index)
++    }
++}
++
++libc_bitflags!(
++    /// Standard interface flags, used by `getifaddrs`
++    pub struct InterfaceFlags: libc::c_int {
++        /// Interface is running. (see
++        /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++        IFF_UP;
++        /// Valid broadcast address set. (see
++        /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++        IFF_BROADCAST;
++        /// Internal debugging flag. (see
++        /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++        IFF_DEBUG;
++        /// Interface is a loopback interface. (see
++        /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++        IFF_LOOPBACK;
++        /// Interface is a point-to-point link. (see
++        /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++        IFF_POINTOPOINT;
++        /// Avoid use of trailers. (see
++        /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++        #[cfg(any(target_os = "android",
++                  target_os = "fuchsia",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos",
++                  target_os = "netbsd",
++                  target_os = "solaris"))]
++        IFF_NOTRAILERS;
++        /// Interface manages own routes.
++        #[cfg(any(target_os = "dragonfly"))]
++        IFF_SMART;
++        /// Resources allocated. (see
++        /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++        #[cfg(any(target_os = "android",
++                  target_os = "dragonfly",
++                  target_os = "freebsd",
++                  target_os = "fuchsia",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos",
++                  target_os = "netbsd",
++                  target_os = "openbsd",
++                  target_os = "solaris"))]
++        IFF_RUNNING;
++        /// No arp protocol, L2 destination address not set. (see
++        /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++        IFF_NOARP;
++        /// Interface is in promiscuous mode. (see
++        /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++        IFF_PROMISC;
++        /// Receive all multicast packets. (see
++        /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++        IFF_ALLMULTI;
++        /// Master of a load balancing bundle. (see
++        /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++        #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
++        IFF_MASTER;
++        /// transmission in progress, tx hardware queue is full
++        #[cfg(any(target_os = "freebsd",
++                  target_os = "macos",
++                  target_os = "netbsd",
++                  target_os = "openbsd",
++                  target_os = "ios"))]
++        IFF_OACTIVE;
++        /// Protocol code on board.
++        #[cfg(target_os = "solaris")]
++        IFF_INTELLIGENT;
++        /// Slave of a load balancing bundle. (see
++        /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++        #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
++        IFF_SLAVE;
++        /// Can't hear own transmissions.
++        #[cfg(any(target_os = "dragonfly",
++                  target_os = "freebsd",
++                  target_os = "macos",
++                  target_os = "netbsd",
++                  target_os = "openbsd",
++                  target_os = "osx"))]
++        IFF_SIMPLEX;
++        /// Supports multicast. (see
++        /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++        IFF_MULTICAST;
++        /// Per link layer defined bit.
++        #[cfg(any(target_os = "dragonfly",
++                  target_os = "freebsd",
++                  target_os = "macos",
++                  target_os = "netbsd",
++                  target_os = "openbsd",
++                  target_os = "ios"))]
++        IFF_LINK0;
++        /// Multicast using broadcast.
++        #[cfg(any(target_os = "solaris"))]
++        IFF_MULTI_BCAST;
++        /// Is able to select media type via ifmap. (see
++        /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++        #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
++        IFF_PORTSEL;
++        /// Per link layer defined bit.
++        #[cfg(any(target_os = "dragonfly",
++                  target_os = "freebsd",
++                  target_os = "macos",
++                  target_os = "netbsd",
++                  target_os = "openbsd",
++                  target_os = "ios"))]
++        IFF_LINK1;
++        /// Non-unique address.
++        #[cfg(any(target_os = "solaris"))]
++        IFF_UNNUMBERED;
++        /// Auto media selection active. (see
++        /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++        #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
++        IFF_AUTOMEDIA;
++        /// Per link layer defined bit.
++        #[cfg(any(target_os = "dragonfly",
++                  target_os = "freebsd",
++                  target_os = "macos",
++                  target_os = "netbsd",
++                  target_os = "openbsd",
++                  target_os = "ios"))]
++        IFF_LINK2;
++        /// Use alternate physical connection.
++        #[cfg(any(target_os = "dragonfly",
++                  target_os = "freebsd",
++                  target_os = "macos",
++                  target_os = "ios"))]
++        IFF_ALTPHYS;
++        /// DHCP controlls interface.
++        #[cfg(any(target_os = "solaris"))]
++        IFF_DHCPRUNNING;
++        /// The addresses are lost when the interface goes down. (see
++        /// [`netdevice(7)`](http://man7.org/linux/man-pages/man7/netdevice.7.html))
++        #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
++        IFF_DYNAMIC;
++        /// Do not advertise.
++        #[cfg(any(target_os = "solaris"))]
++        IFF_PRIVATE;
++        /// Driver signals L1 up. Volatile.
++        #[cfg(any(target_os = "fuchsia", target_os = "linux"))]
++        IFF_LOWER_UP;
++        /// Interface is in polling mode.
++        #[cfg(any(target_os = "dragonfly"))]
++        IFF_POLLING_COMPAT;
++        /// Unconfigurable using ioctl(2).
++        #[cfg(any(target_os = "freebsd"))]
++        IFF_CANTCONFIG;
++        /// Do not transmit packets.
++        #[cfg(any(target_os = "solaris"))]
++        IFF_NOXMIT;
++        /// Driver signals dormant. Volatile.
++        #[cfg(any(target_os = "fuchsia", target_os = "linux"))]
++        IFF_DORMANT;
++        /// User-requested promisc mode.
++        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++        IFF_PPROMISC;
++        /// Just on-link subnet.
++        #[cfg(any(target_os = "solaris"))]
++        IFF_NOLOCAL;
++        /// Echo sent packets. Volatile.
++        #[cfg(any(target_os = "fuchsia", target_os = "linux"))]
++        IFF_ECHO;
++        /// User-requested monitor mode.
++        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++        IFF_MONITOR;
++        /// Address is deprecated.
++        #[cfg(any(target_os = "solaris"))]
++        IFF_DEPRECATED;
++        /// Static ARP.
++        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++        IFF_STATICARP;
++        /// Address from stateless addrconf.
++        #[cfg(any(target_os = "solaris"))]
++        IFF_ADDRCONF;
++        /// Interface is in polling mode.
++        #[cfg(any(target_os = "dragonfly"))]
++        IFF_NPOLLING;
++        /// Router on interface.
++        #[cfg(any(target_os = "solaris"))]
++        IFF_ROUTER;
++        /// Interface is in polling mode.
++        #[cfg(any(target_os = "dragonfly"))]
++        IFF_IDIRECT;
++        /// Interface is winding down
++        #[cfg(any(target_os = "freebsd"))]
++        IFF_DYING;
++        /// No NUD on interface.
++        #[cfg(any(target_os = "solaris"))]
++        IFF_NONUD;
++        /// Interface is being renamed
++        #[cfg(any(target_os = "freebsd"))]
++        IFF_RENAMING;
++        /// Anycast address.
++        #[cfg(any(target_os = "solaris"))]
++        IFF_ANYCAST;
++        /// Don't exchange routing info.
++        #[cfg(any(target_os = "solaris"))]
++        IFF_NORTEXCH;
++        /// Do not provide packet information
++        #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
++        IFF_NO_PI as libc::c_int;
++        /// TUN device (no Ethernet headers) 
++        #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
++        IFF_TUN as libc::c_int;
++        /// TAP device
++        #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
++        IFF_TAP as libc::c_int;
++        /// IPv4 interface.
++        #[cfg(any(target_os = "solaris"))]
++        IFF_IPV4;
++        /// IPv6 interface.
++        #[cfg(any(target_os = "solaris"))]
++        IFF_IPV6;
++        /// in.mpathd test address
++        #[cfg(any(target_os = "solaris"))]
++        IFF_NOFAILOVER;
++        /// Interface has failed
++        #[cfg(any(target_os = "solaris"))]
++        IFF_FAILED;
++        /// Interface is a hot-spare
++        #[cfg(any(target_os = "solaris"))]
++        IFF_STANDBY;
++        /// Functioning but not used
++        #[cfg(any(target_os = "solaris"))]
++        IFF_INACTIVE;
++        /// Interface is offline
++        #[cfg(any(target_os = "solaris"))]
++        IFF_OFFLINE;
++        #[cfg(any(target_os = "solaris"))]
++        IFF_COS_ENABLED;
++        /// Prefer as source addr.
++        #[cfg(any(target_os = "solaris"))]
++        IFF_PREFERRED;
++        /// RFC3041
++        #[cfg(any(target_os = "solaris"))]
++        IFF_TEMPORARY;
++        /// MTU set with SIOCSLIFMTU
++        #[cfg(any(target_os = "solaris"))]
++        IFF_FIXEDMTU;
++        /// Cannot send / receive packets
++        #[cfg(any(target_os = "solaris"))]
++        IFF_VIRTUAL;
++        /// Local address in use
++        #[cfg(any(target_os = "solaris"))]
++        IFF_DUPLICATE;
++        /// IPMP IP interface
++        #[cfg(any(target_os = "solaris"))]
++        IFF_IPMP;
++    }
++);
+diff --git a/third_party/rust/nix-0.15.0/src/net/mod.rs b/third_party/rust/nix-0.15.0/src/net/mod.rs
+new file mode 100644
+index 0000000000000..079fcfde6fd44
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/net/mod.rs
+@@ -0,0 +1,4 @@
++//! Functionality involving network interfaces
++// To avoid clashing with the keyword "if", we use "if_" as the module name.
++// The original header is called "net/if.h".
++pub mod if_;
+diff --git a/third_party/rust/nix-0.15.0/src/poll.rs b/third_party/rust/nix-0.15.0/src/poll.rs
+new file mode 100644
+index 0000000000000..c603611e3176f
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/poll.rs
+@@ -0,0 +1,143 @@
++//! Wait for events to trigger on specific file descriptors
++#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
++use sys::time::TimeSpec;
++#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
++use sys::signal::SigSet;
++use std::os::unix::io::RawFd;
++
++use libc;
++use Result;
++use errno::Errno;
++
++/// This is a wrapper around `libc::pollfd`.
++///
++/// It's meant to be used as an argument to the [`poll`](fn.poll.html) and
++/// [`ppoll`](fn.ppoll.html) functions to specify the events of interest
++/// for a specific file descriptor.
++///
++/// After a call to `poll` or `ppoll`, the events that occured can be
++/// retrieved by calling [`revents()`](#method.revents) on the `PollFd`.
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct PollFd {
++    pollfd: libc::pollfd,
++}
++
++impl PollFd {
++    /// Creates a new `PollFd` specifying the events of interest
++    /// for a given file descriptor.
++    pub fn new(fd: RawFd, events: PollFlags) -> PollFd {
++        PollFd {
++            pollfd: libc::pollfd {
++                fd: fd,
++                events: events.bits(),
++                revents: PollFlags::empty().bits(),
++            },
++        }
++    }
++
++    /// Returns the events that occured in the last call to `poll` or `ppoll`.
++    pub fn revents(&self) -> Option<PollFlags> {
++        PollFlags::from_bits(self.pollfd.revents)
++    }
++}
++
++libc_bitflags! {
++    /// These flags define the different events that can be monitored by `poll` and `ppoll`
++    pub struct PollFlags: libc::c_short {
++        /// There is data to read.
++        POLLIN;
++        /// There is some exceptional condition on the file descriptor.
++        ///
++        /// Possibilities include:
++        ///
++        /// *  There is out-of-band data on a TCP socket (see
++        ///    [tcp(7)](http://man7.org/linux/man-pages/man7/tcp.7.html)).
++        /// *  A pseudoterminal master in packet mode has seen a state
++        ///    change on the slave (see
++        ///    [ioctl_tty(2)](http://man7.org/linux/man-pages/man2/ioctl_tty.2.html)).
++        /// *  A cgroup.events file has been modified (see
++        ///    [cgroups(7)](http://man7.org/linux/man-pages/man7/cgroups.7.html)).
++        POLLPRI;
++        /// Writing is now possible, though a write larger that the
++        /// available space in a socket or pipe will still block (unless
++        /// `O_NONBLOCK` is set).
++        POLLOUT;
++        /// Equivalent to [`POLLIN`](constant.POLLIN.html)
++        POLLRDNORM;
++        /// Equivalent to [`POLLOUT`](constant.POLLOUT.html)
++        POLLWRNORM;
++        /// Priority band data can be read (generally unused on Linux).
++        POLLRDBAND;
++        /// Priority data may be written.
++        POLLWRBAND;
++        /// Error condition (only returned in
++        /// [`PollFd::revents`](struct.PollFd.html#method.revents);
++        /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)).
++        /// This bit is also set for a file descriptor referring to the
++        /// write end of a pipe when the read end has been closed.
++        POLLERR;
++        /// Hang up (only returned in [`PollFd::revents`](struct.PollFd.html#method.revents);
++        /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)).
++        /// Note that when reading from a channel such as a pipe or a stream
++        /// socket, this event merely indicates that the peer closed its
++        /// end of the channel.  Subsequent reads from the channel will
++        /// return 0 (end of file) only after all outstanding data in the
++        /// channel has been consumed.
++        POLLHUP;
++        /// Invalid request: `fd` not open (only returned in
++        /// [`PollFd::revents`](struct.PollFd.html#method.revents);
++        /// ignored in [`PollFd::new`](struct.PollFd.html#method.new)).
++        POLLNVAL;
++    }
++}
++
++/// `poll` waits for one of a set of file descriptors to become ready to perform I/O.
++/// ([`poll(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html))
++///
++/// `fds` contains all [`PollFd`](struct.PollFd.html) to poll.
++/// The function will return as soon as any event occur for any of these `PollFd`s.
++///
++/// The `timeout` argument specifies the number of milliseconds that `poll()`
++/// should block waiting for a file descriptor to become ready.  The call
++/// will block until either:
++///
++/// *  a file descriptor becomes ready;
++/// *  the call is interrupted by a signal handler; or
++/// *  the timeout expires.
++///
++/// Note that the timeout interval will be rounded up to the system clock
++/// granularity, and kernel scheduling delays mean that the blocking
++/// interval may overrun by a small amount.  Specifying a negative value
++/// in timeout means an infinite timeout.  Specifying a timeout of zero
++/// causes `poll()` to return immediately, even if no file descriptors are
++/// ready.
++pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result<libc::c_int> {
++    let res = unsafe {
++        libc::poll(fds.as_mut_ptr() as *mut libc::pollfd,
++                   fds.len() as libc::nfds_t,
++                   timeout)
++    };
++
++    Errno::result(res)
++}
++
++/// `ppoll()` allows an application to safely wait until either a file
++/// descriptor becomes ready or until a signal is caught.
++/// ([`poll(2)`](http://man7.org/linux/man-pages/man2/poll.2.html))
++///
++/// `ppoll` behaves like `poll`, but let you specify what signals may interrupt it
++/// with the `sigmask` argument.
++///
++#[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
++pub fn ppoll(fds: &mut [PollFd], timeout: TimeSpec, sigmask: SigSet) -> Result<libc::c_int> {
++
++
++    let res = unsafe {
++        libc::ppoll(fds.as_mut_ptr() as *mut libc::pollfd,
++                    fds.len() as libc::nfds_t,
++                    timeout.as_ref(),
++                    sigmask.as_ref())
++    };
++    Errno::result(res)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/pty.rs b/third_party/rust/nix-0.15.0/src/pty.rs
+new file mode 100644
+index 0000000000000..db012d8158c53
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/pty.rs
+@@ -0,0 +1,326 @@
++//! Create master and slave virtual pseudo-terminals (PTYs)
++
++use libc;
++
++pub use libc::pid_t as SessionId;
++pub use libc::winsize as Winsize;
++
++use std::ffi::CStr;
++use std::mem;
++use std::os::unix::prelude::*;
++
++use sys::termios::Termios;
++use unistd::ForkResult;
++use {Result, Error, fcntl};
++use errno::Errno;
++
++/// Representation of a master/slave pty pair
++///
++/// This is returned by `openpty`.  Note that this type does *not* implement `Drop`, so the user
++/// must manually close the file descriptors.
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct OpenptyResult {
++    /// The master port in a virtual pty pair
++    pub master: RawFd,
++    /// The slave port in a virtual pty pair
++    pub slave: RawFd,
++}
++
++/// Representation of a master with a forked pty
++///
++/// This is returned by `forkpty`. Note that this type does *not* implement `Drop`, so the user
++/// must manually close the file descriptors.
++#[derive(Clone, Copy, Debug)]
++pub struct ForkptyResult {
++    /// The master port in a virtual pty pair
++    pub master: RawFd,
++    /// Metadata about forked process
++    pub fork_result: ForkResult,
++}
++
++
++/// Representation of the Master device in a master/slave pty pair
++///
++/// 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)]
++pub struct PtyMaster(RawFd);
++
++impl AsRawFd for PtyMaster {
++    fn as_raw_fd(&self) -> RawFd {
++        self.0
++    }
++}
++
++impl IntoRawFd for PtyMaster {
++    fn into_raw_fd(self) -> RawFd {
++        let fd = self.0;
++        mem::forget(self);
++        fd
++    }
++}
++
++impl Drop for PtyMaster {
++    fn drop(&mut self) {
++        // On drop, we ignore errors like EINTR and EIO because there's no clear
++        // way to handle them, we can't return anything, and (on FreeBSD at
++        // least) the file descriptor is deallocated in these cases.  However,
++        // we must panic on EBADF, because it is always an error to close an
++        // invalid file descriptor.  That frequently indicates a double-close
++        // condition, which can cause confusing errors for future I/O
++        // operations.
++        let e = ::unistd::close(self.0);
++        if e == Err(Error::Sys(Errno::EBADF)) {
++            panic!("Closing an invalid file descriptor!");
++        };
++    }
++}
++
++/// Grant access to a slave pseudoterminal (see
++/// [`grantpt(3)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/grantpt.html))
++///
++/// `grantpt()` changes the mode and owner of the slave pseudoterminal device corresponding to the
++/// master pseudoterminal referred to by `fd`. This is a necessary step towards opening the slave.
++#[inline]
++pub fn grantpt(fd: &PtyMaster) -> Result<()> {
++    if unsafe { libc::grantpt(fd.as_raw_fd()) } < 0 {
++        return Err(Error::last());
++    }
++
++    Ok(())
++}
++
++/// Open a pseudoterminal device (see
++/// [`posix_openpt(3)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_openpt.html))
++///
++/// `posix_openpt()` returns a file descriptor to an existing unused pseuterminal master device.
++///
++/// # Examples
++///
++/// A common use case with this function is to open both a master and slave PTY pair. This can be
++/// done as follows:
++///
++/// ```
++/// use std::path::Path;
++/// use nix::fcntl::{OFlag, open};
++/// use nix::pty::{grantpt, posix_openpt, ptsname, unlockpt};
++/// use nix::sys::stat::Mode;
++///
++/// # #[allow(dead_code)]
++/// # fn run() -> nix::Result<()> {
++/// // Open a new PTY master
++/// let master_fd = posix_openpt(OFlag::O_RDWR)?;
++///
++/// // Allow a slave to be generated for it
++/// grantpt(&master_fd)?;
++/// unlockpt(&master_fd)?;
++///
++/// // Get the name of the slave
++/// let slave_name = unsafe { ptsname(&master_fd) }?;
++///
++/// // Try to open the slave
++/// let _slave_fd = open(Path::new(&slave_name), OFlag::O_RDWR, Mode::empty())?;
++/// # Ok(())
++/// # }
++/// ```
++#[inline]
++pub fn posix_openpt(flags: fcntl::OFlag) -> Result<PtyMaster> {
++    let fd = unsafe {
++        libc::posix_openpt(flags.bits())
++    };
++
++    if fd < 0 {
++        return Err(Error::last());
++    }
++
++    Ok(PtyMaster(fd))
++}
++
++/// Get the name of the slave pseudoterminal (see
++/// [`ptsname(3)`](http://man7.org/linux/man-pages/man3/ptsname.3.html))
++///
++/// `ptsname()` returns the name of the slave pseudoterminal device corresponding to the master
++/// referred to by `fd`.
++///
++/// This value is useful for opening the slave pty once the master has already been opened with
++/// `posix_openpt()`.
++///
++/// # Safety
++///
++/// `ptsname()` mutates global variables and is *not* threadsafe.
++/// Mutating global variables is always considered `unsafe` by Rust and this
++/// function is marked as `unsafe` to reflect that.
++///
++/// For a threadsafe and non-`unsafe` alternative on Linux, see `ptsname_r()`.
++#[inline]
++pub unsafe fn ptsname(fd: &PtyMaster) -> Result<String> {
++    let name_ptr = libc::ptsname(fd.as_raw_fd());
++    if name_ptr.is_null() {
++        return Err(Error::last());
++    }
++
++    let name = CStr::from_ptr(name_ptr);
++    Ok(name.to_string_lossy().into_owned())
++}
++
++/// Get the name of the slave pseudoterminal (see
++/// [`ptsname(3)`](http://man7.org/linux/man-pages/man3/ptsname.3.html))
++///
++/// `ptsname_r()` returns the name of the slave pseudoterminal device corresponding to the master
++/// referred to by `fd`. This is the threadsafe version of `ptsname()`, but it is not part of the
++/// POSIX standard and is instead a Linux-specific extension.
++///
++/// This value is useful for opening the slave ptty once the master has already been opened with
++/// `posix_openpt()`.
++#[cfg(any(target_os = "android", target_os = "linux"))]
++#[inline]
++pub fn ptsname_r(fd: &PtyMaster) -> Result<String> {
++    let mut name_buf = vec![0u8; 64];
++    let name_buf_ptr = name_buf.as_mut_ptr() as *mut libc::c_char;
++    if unsafe { libc::ptsname_r(fd.as_raw_fd(), name_buf_ptr, name_buf.capacity()) } != 0 {
++        return Err(Error::last());
++    }
++
++    // Find the first null-character terminating this string. This is guaranteed to succeed if the
++    // return value of `libc::ptsname_r` is 0.
++    let null_index = name_buf.iter().position(|c| *c == b'\0').unwrap();
++    name_buf.truncate(null_index);
++
++    let name = String::from_utf8(name_buf)?;
++    Ok(name)
++}
++
++/// Unlock a pseudoterminal master/slave pseudoterminal pair (see
++/// [`unlockpt(3)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/unlockpt.html))
++///
++/// `unlockpt()` unlocks the slave pseudoterminal device corresponding to the master pseudoterminal
++/// referred to by `fd`. This must be called before trying to open the slave side of a
++/// pseuoterminal.
++#[inline]
++pub fn unlockpt(fd: &PtyMaster) -> Result<()> {
++    if unsafe { libc::unlockpt(fd.as_raw_fd()) } < 0 {
++        return Err(Error::last());
++    }
++
++    Ok(())
++}
++
++
++/// Create a new pseudoterminal, returning the slave and master file descriptors
++/// in `OpenptyResult`
++/// (see [`openpty`](http://man7.org/linux/man-pages/man3/openpty.3.html)).
++///
++/// If `winsize` is not `None`, the window size of the slave will be set to
++/// the values in `winsize`. If `termios` is not `None`, the pseudoterminal's
++/// terminal settings of the slave will be set to the values in `termios`.
++#[inline]
++pub fn openpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>>>(winsize: T, termios: U) -> Result<OpenptyResult> {
++    use std::ptr;
++
++    let mut slave: libc::c_int = unsafe { mem::uninitialized() };
++    let mut master: libc::c_int = unsafe { mem::uninitialized() };
++    let ret = {
++        match (termios.into(), winsize.into()) {
++            (Some(termios), Some(winsize)) => {
++                let inner_termios = termios.get_libc_termios();
++                unsafe {
++                    libc::openpty(
++                        &mut master,
++                        &mut slave,
++                        ptr::null_mut(),
++                        &*inner_termios as *const libc::termios as *mut _,
++                        winsize as *const Winsize as *mut _,
++                    )
++                }
++            }
++            (None, Some(winsize)) => {
++                unsafe {
++                    libc::openpty(
++                        &mut master,
++                        &mut slave,
++                        ptr::null_mut(),
++                        ptr::null_mut(),
++                        winsize as *const Winsize as *mut _,
++                    )
++                }
++            }
++            (Some(termios), None) => {
++                let inner_termios = termios.get_libc_termios();
++                unsafe {
++                    libc::openpty(
++                        &mut master,
++                        &mut slave,
++                        ptr::null_mut(),
++                        &*inner_termios as *const libc::termios as *mut _,
++                        ptr::null_mut(),
++                    )
++                }
++            }
++            (None, None) => {
++                unsafe {
++                    libc::openpty(
++                        &mut master,
++                        &mut slave,
++                        ptr::null_mut(),
++                        ptr::null_mut(),
++                        ptr::null_mut(),
++                    )
++                }
++            }
++        }
++    };
++
++    Errno::result(ret)?;
++
++    Ok(OpenptyResult {
++        master: master,
++        slave: slave,
++    })
++}
++
++/// Create a new pseudoterminal, returning the master file descriptor and forked pid.
++/// in `ForkptyResult`
++/// (see [`forkpty`](http://man7.org/linux/man-pages/man3/forkpty.3.html)).
++///
++/// If `winsize` is not `None`, the window size of the slave will be set to
++/// the values in `winsize`. If `termios` is not `None`, the pseudoterminal's
++/// terminal settings of the slave will be set to the values in `termios`.
++pub fn forkpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>>>(
++    winsize: T,
++    termios: U,
++) -> Result<ForkptyResult> {
++    use std::ptr;
++    use unistd::Pid;
++    use unistd::ForkResult::*;
++
++    let mut master: libc::c_int = unsafe { mem::uninitialized() };
++
++    let term = match termios.into() {
++        Some(termios) => {
++            let inner_termios = termios.get_libc_termios();
++            &*inner_termios as *const libc::termios as *mut _
++        },
++        None => ptr::null_mut(),
++    };
++
++    let win = winsize
++        .into()
++        .map(|ws| ws as *const Winsize as *mut _)
++        .unwrap_or(ptr::null_mut());
++
++    let res = unsafe {
++        libc::forkpty(&mut master, ptr::null_mut(), term, win)
++    };
++
++    let fork_result = Errno::result(res).map(|res| match res {
++        0 => Child,
++        res => Parent { child: Pid::from_raw(res) },
++    })?;
++
++    Ok(ForkptyResult {
++        master: master,
++        fork_result: fork_result,
++    })
++}
++
+diff --git a/third_party/rust/nix-0.15.0/src/sched.rs b/third_party/rust/nix-0.15.0/src/sched.rs
+new file mode 100644
+index 0000000000000..67188c57eef7d
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sched.rs
+@@ -0,0 +1,147 @@
++use libc;
++use {Errno, Result};
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub use self::sched_linux_like::*;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++mod sched_linux_like {
++    use errno::Errno;
++    use libc::{self, c_int, c_void};
++    use std::mem;
++    use std::option::Option;
++    use std::os::unix::io::RawFd;
++    use unistd::Pid;
++    use {Error, Result};
++
++    // For some functions taking with a parameter of type CloneFlags,
++    // only a subset of these flags have an effect.
++    libc_bitflags! {
++        pub struct CloneFlags: c_int {
++            CLONE_VM;
++            CLONE_FS;
++            CLONE_FILES;
++            CLONE_SIGHAND;
++            CLONE_PTRACE;
++            CLONE_VFORK;
++            CLONE_PARENT;
++            CLONE_THREAD;
++            CLONE_NEWNS;
++            CLONE_SYSVSEM;
++            CLONE_SETTLS;
++            CLONE_PARENT_SETTID;
++            CLONE_CHILD_CLEARTID;
++            CLONE_DETACHED;
++            CLONE_UNTRACED;
++            CLONE_CHILD_SETTID;
++            CLONE_NEWCGROUP;
++            CLONE_NEWUTS;
++            CLONE_NEWIPC;
++            CLONE_NEWUSER;
++            CLONE_NEWPID;
++            CLONE_NEWNET;
++            CLONE_IO;
++        }
++    }
++
++    pub type CloneCb<'a> = Box<dyn FnMut() -> isize + 'a>;
++
++    #[repr(C)]
++    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++    pub struct CpuSet {
++        cpu_set: libc::cpu_set_t,
++    }
++
++    impl CpuSet {
++        pub fn new() -> CpuSet {
++            CpuSet {
++                cpu_set: unsafe { mem::zeroed() },
++            }
++        }
++
++        pub fn is_set(&self, field: usize) -> Result<bool> {
++            if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
++                Err(Error::Sys(Errno::EINVAL))
++            } else {
++                Ok(unsafe { libc::CPU_ISSET(field, &self.cpu_set) })
++            }
++        }
++
++        pub fn set(&mut self, field: usize) -> Result<()> {
++            if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
++                Err(Error::Sys(Errno::EINVAL))
++            } else {
++                Ok(unsafe { libc::CPU_SET(field, &mut self.cpu_set) })
++            }
++        }
++
++        pub fn unset(&mut self, field: usize) -> Result<()> {
++            if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
++                Err(Error::Sys(Errno::EINVAL))
++            } else {
++                Ok(unsafe { libc::CPU_CLR(field, &mut self.cpu_set) })
++            }
++        }
++    }
++
++    pub fn sched_setaffinity(pid: Pid, cpuset: &CpuSet) -> Result<()> {
++        let res = unsafe {
++            libc::sched_setaffinity(
++                pid.into(),
++                mem::size_of::<CpuSet>() as libc::size_t,
++                &cpuset.cpu_set,
++            )
++        };
++
++        Errno::result(res).map(drop)
++    }
++
++    pub fn clone(
++        mut cb: CloneCb,
++        stack: &mut [u8],
++        flags: CloneFlags,
++        signal: Option<c_int>,
++    ) -> Result<Pid> {
++        extern "C" fn callback(data: *mut CloneCb) -> c_int {
++            let cb: &mut CloneCb = unsafe { &mut *data };
++            (*cb)() as c_int
++        }
++
++        let res = unsafe {
++            let combined = flags.bits() | signal.unwrap_or(0);
++            let ptr = stack.as_mut_ptr().offset(stack.len() as isize);
++            let ptr_aligned = ptr.offset((ptr as usize % 16) as isize * -1);
++            libc::clone(
++                mem::transmute(
++                    callback as extern "C" fn(*mut Box<dyn FnMut() -> isize>) -> i32,
++                ),
++                ptr_aligned as *mut c_void,
++                combined,
++                &mut cb as *mut _ as *mut c_void,
++            )
++        };
++
++        Errno::result(res).map(Pid::from_raw)
++    }
++
++    pub fn unshare(flags: CloneFlags) -> Result<()> {
++        let res = unsafe { libc::unshare(flags.bits()) };
++
++        Errno::result(res).map(drop)
++    }
++
++    pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> {
++        let res = unsafe { libc::setns(fd, nstype.bits()) };
++
++        Errno::result(res).map(drop)
++    }
++}
++
++/// Explicitly yield the processor to other threads.
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_yield.html)
++pub fn sched_yield() -> Result<()> {
++    let res = unsafe { libc::sched_yield() };
++
++    Errno::result(res).map(drop)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/aio.rs b/third_party/rust/nix-0.15.0/src/sys/aio.rs
+new file mode 100644
+index 0000000000000..9258a0657cc8a
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/aio.rs
+@@ -0,0 +1,1280 @@
++// vim: tw=80
++//! POSIX Asynchronous I/O
++//!
++//! The POSIX AIO interface is used for asynchronous I/O on files and disk-like
++//! devices.  It supports [`read`](struct.AioCb.html#method.read),
++//! [`write`](struct.AioCb.html#method.write), and
++//! [`fsync`](struct.AioCb.html#method.fsync) operations.  Completion
++//! notifications can optionally be delivered via
++//! [signals](../signal/enum.SigevNotify.html#variant.SigevSignal), via the
++//! [`aio_suspend`](fn.aio_suspend.html) function, or via polling.  Some
++//! platforms support other completion
++//! notifications, such as
++//! [kevent](../signal/enum.SigevNotify.html#variant.SigevKevent).
++//!
++//! Multiple operations may be submitted in a batch with
++//! [`lio_listio`](fn.lio_listio.html), though the standard does not guarantee
++//! that they will be executed atomically.
++//!
++//! Outstanding operations may be cancelled with
++//! [`cancel`](struct.AioCb.html#method.cancel) or
++//! [`aio_cancel_all`](fn.aio_cancel_all.html), though the operating system may
++//! not support this for all filesystems and devices.
++
++use {Error, Result};
++use errno::Errno;
++use std::os::unix::io::RawFd;
++use libc::{c_void, off_t, size_t};
++use libc;
++use std::borrow::{Borrow, BorrowMut};
++use std::fmt;
++use std::fmt::Debug;
++use std::marker::PhantomData;
++use std::mem;
++use std::ptr::{null, null_mut};
++use sys::signal::*;
++use std::thread;
++use sys::time::TimeSpec;
++
++libc_enum! {
++    /// Mode for `AioCb::fsync`.  Controls whether only data or both data and
++    /// metadata are synced.
++    #[repr(i32)]
++    pub enum AioFsyncMode {
++        /// do it like `fsync`
++        O_SYNC,
++        /// on supported operating systems only, do it like `fdatasync`
++        #[cfg(any(target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos",
++                  target_os = "netbsd",
++                  target_os = "openbsd"))]
++        O_DSYNC
++    }
++}
++
++libc_enum! {
++    /// When used with [`lio_listio`](fn.lio_listio.html), determines whether a
++    /// given `aiocb` should be used for a read operation, a write operation, or
++    /// ignored.  Has no effect for any other aio functions.
++    #[repr(i32)]
++    pub enum LioOpcode {
++        LIO_NOP,
++        LIO_WRITE,
++        LIO_READ,
++    }
++}
++
++libc_enum! {
++    /// Mode for [`lio_listio`](fn.lio_listio.html)
++    #[repr(i32)]
++    pub enum LioMode {
++        /// Requests that [`lio_listio`](fn.lio_listio.html) block until all
++        /// requested operations have been completed
++        LIO_WAIT,
++        /// Requests that [`lio_listio`](fn.lio_listio.html) return immediately
++        LIO_NOWAIT,
++    }
++}
++
++/// Return values for [`AioCb::cancel`](struct.AioCb.html#method.cancel) and
++/// [`aio_cancel_all`](fn.aio_cancel_all.html)
++#[repr(i32)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub enum AioCancelStat {
++    /// All outstanding requests were canceled
++    AioCanceled = libc::AIO_CANCELED,
++    /// Some requests were not canceled.  Their status should be checked with
++    /// `AioCb::error`
++    AioNotCanceled = libc::AIO_NOTCANCELED,
++    /// All of the requests have already finished
++    AioAllDone = libc::AIO_ALLDONE,
++}
++
++/// Owns (uniquely or shared) a memory buffer to keep it from `Drop`ing while
++/// the kernel has a pointer to it.
++pub enum Buffer<'a> {
++    /// No buffer to own.
++    ///
++    /// Used for operations like `aio_fsync` that have no data, or for unsafe
++    /// operations that work with raw pointers.
++    None,
++    /// Keeps a reference to a slice
++    Phantom(PhantomData<&'a mut [u8]>),
++    /// Generic thing that keeps a buffer from dropping
++    BoxedSlice(Box<dyn Borrow<[u8]>>),
++    /// Generic thing that keeps a mutable buffer from dropping
++    BoxedMutSlice(Box<dyn BorrowMut<[u8]>>),
++}
++
++impl<'a> Debug for Buffer<'a> {
++    // Note: someday it may be possible to Derive Debug for a trait object, but
++    // not today.
++    // https://github.com/rust-lang/rust/issues/1563
++    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
++        match *self {
++            Buffer::None => write!(fmt, "None"),
++            Buffer::Phantom(p) => p.fmt(fmt),
++            Buffer::BoxedSlice(ref bs) => {
++                let borrowed : &dyn Borrow<[u8]> = bs.borrow();
++                write!(fmt, "BoxedSlice({:?})",
++                    borrowed as *const dyn Borrow<[u8]>)
++            },
++            Buffer::BoxedMutSlice(ref bms) => {
++                let borrowed : &dyn BorrowMut<[u8]> = bms.borrow();
++                write!(fmt, "BoxedMutSlice({:?})",
++                    borrowed as *const dyn BorrowMut<[u8]>)
++            }
++        }
++    }
++}
++
++/// AIO Control Block.
++///
++/// The basic structure used by all aio functions.  Each `AioCb` represents one
++/// I/O request.
++pub struct AioCb<'a> {
++    aiocb: libc::aiocb,
++    /// Tracks whether the buffer pointed to by `libc::aiocb.aio_buf` is mutable
++    mutable: bool,
++    /// Could this `AioCb` potentially have any in-kernel state?
++    in_progress: bool,
++    /// Optionally keeps a reference to the data.
++    ///
++    /// Used to keep buffers from `Drop`'ing, and may be returned once the
++    /// `AioCb` is completed by [`buffer`](#method.buffer).
++    buffer: Buffer<'a>
++}
++
++impl<'a> AioCb<'a> {
++    /// Remove the inner `Buffer` and return it
++    ///
++    /// It is an error to call this method while the `AioCb` is still in
++    /// progress.
++    pub fn buffer(&mut self) -> Buffer<'a> {
++        assert!(!self.in_progress);
++        let mut x = Buffer::None;
++        mem::swap(&mut self.buffer, &mut x);
++        x
++    }
++
++    /// Remove the inner boxed slice, if any, and return it.
++    ///
++    /// The returned value will be the argument that was passed to
++    /// `from_boxed_slice` when this `AioCb` was created.
++    ///
++    /// It is an error to call this method while the `AioCb` is still in
++    /// progress.
++    pub fn boxed_slice(&mut self) -> Option<Box<dyn Borrow<[u8]>>> {
++        assert!(!self.in_progress, "Can't remove the buffer from an AioCb that's still in-progress.  Did you forget to call aio_return?");
++        if let Buffer::BoxedSlice(_) = self.buffer {
++            let mut oldbuffer = Buffer::None;
++            mem::swap(&mut self.buffer, &mut oldbuffer);
++            if let Buffer::BoxedSlice(inner) = oldbuffer {
++                Some(inner)
++            } else {
++                unreachable!();
++            }
++        } else {
++            None
++        }
++    }
++
++    /// Remove the inner boxed mutable slice, if any, and return it.
++    ///
++    /// The returned value will be the argument that was passed to
++    /// `from_boxed_mut_slice` when this `AioCb` was created.
++    ///
++    /// It is an error to call this method while the `AioCb` is still in
++    /// progress.
++    pub fn boxed_mut_slice(&mut self) -> Option<Box<dyn BorrowMut<[u8]>>> {
++        assert!(!self.in_progress, "Can't remove the buffer from an AioCb that's still in-progress.  Did you forget to call aio_return?");
++        if let Buffer::BoxedMutSlice(_) = self.buffer {
++            let mut oldbuffer = Buffer::None;
++            mem::swap(&mut self.buffer, &mut oldbuffer);
++            if let Buffer::BoxedMutSlice(inner) = oldbuffer {
++                Some(inner)
++            } else {
++                unreachable!();
++            }
++        } else {
++            None
++        }
++    }
++
++    /// Returns the underlying file descriptor associated with the `AioCb`
++    pub fn fd(&self) -> RawFd {
++        self.aiocb.aio_fildes
++    }
++
++    /// Constructs a new `AioCb` with no associated buffer.
++    ///
++    /// The resulting `AioCb` structure is suitable for use with `AioCb::fsync`.
++    ///
++    /// # Parameters
++    ///
++    /// * `fd`:           File descriptor.  Required for all aio functions.
++    /// * `prio`:         If POSIX Prioritized IO is supported, then the
++    ///                   operation will be prioritized at the process's
++    ///                   priority level minus `prio`.
++    /// * `sigev_notify`: Determines how you will be notified of event
++    ///                    completion.
++    ///
++    /// # Examples
++    ///
++    /// Create an `AioCb` from a raw file descriptor and use it for an
++    /// [`fsync`](#method.fsync) operation.
++    ///
++    /// ```
++    /// # extern crate tempfile;
++    /// # extern crate nix;
++    /// # use nix::errno::Errno;
++    /// # use nix::Error;
++    /// # use nix::sys::aio::*;
++    /// # use nix::sys::signal::SigevNotify::SigevNone;
++    /// # use std::{thread, time};
++    /// # use std::os::unix::io::AsRawFd;
++    /// # use tempfile::tempfile;
++    /// # fn main() {
++    /// let f = tempfile().unwrap();
++    /// let mut aiocb = AioCb::from_fd( f.as_raw_fd(), 0, SigevNone);
++    /// aiocb.fsync(AioFsyncMode::O_SYNC).expect("aio_fsync failed early");
++    /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
++    ///     thread::sleep(time::Duration::from_millis(10));
++    /// }
++    /// aiocb.aio_return().expect("aio_fsync failed late");
++    /// # }
++    /// ```
++    pub fn from_fd(fd: RawFd, prio: libc::c_int,
++                    sigev_notify: SigevNotify) -> AioCb<'a> {
++        let mut a = AioCb::common_init(fd, prio, sigev_notify);
++        a.aio_offset = 0;
++        a.aio_nbytes = 0;
++        a.aio_buf = null_mut();
++
++        AioCb {
++            aiocb: a,
++            mutable: false,
++            in_progress: false,
++            buffer: Buffer::None
++        }
++    }
++
++    /// Constructs a new `AioCb` from a mutable slice.
++    ///
++    /// The resulting `AioCb` will be suitable for both read and write
++    /// operations, but only if the borrow checker can guarantee that the slice
++    /// will outlive the `AioCb`.  That will usually be the case if the `AioCb`
++    /// is stack-allocated.  If the borrow checker gives you trouble, try using
++    /// [`from_boxed_mut_slice`](#method.from_boxed_mut_slice) instead.
++    ///
++    /// # Parameters
++    ///
++    /// * `fd`:           File descriptor.  Required for all aio functions.
++    /// * `offs`:         File offset
++    /// * `buf`:          A memory buffer
++    /// * `prio`:         If POSIX Prioritized IO is supported, then the
++    ///                   operation will be prioritized at the process's
++    ///                   priority level minus `prio`
++    /// * `sigev_notify`: Determines how you will be notified of event
++    ///                   completion.
++    /// * `opcode`:       This field is only used for `lio_listio`.  It
++    ///                   determines which operation to use for this individual
++    ///                   aiocb
++    ///
++    /// # Examples
++    ///
++    /// Create an `AioCb` from a mutable slice and read into it.
++    ///
++    /// ```
++    /// # extern crate tempfile;
++    /// # extern crate nix;
++    /// # use nix::errno::Errno;
++    /// # use nix::Error;
++    /// # use nix::sys::aio::*;
++    /// # use nix::sys::signal::SigevNotify;
++    /// # use std::{thread, time};
++    /// # use std::io::Write;
++    /// # use std::os::unix::io::AsRawFd;
++    /// # use tempfile::tempfile;
++    /// # fn main() {
++    /// const INITIAL: &[u8] = b"abcdef123456";
++    /// const LEN: usize = 4;
++    /// let mut rbuf = vec![0; LEN];
++    /// let mut f = tempfile().unwrap();
++    /// f.write_all(INITIAL).unwrap();
++    /// {
++    ///     let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(),
++    ///         2,   //offset
++    ///         &mut rbuf,
++    ///         0,   //priority
++    ///         SigevNotify::SigevNone,
++    ///         LioOpcode::LIO_NOP);
++    ///     aiocb.read().unwrap();
++    ///     while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
++    ///         thread::sleep(time::Duration::from_millis(10));
++    ///     }
++    ///     assert_eq!(aiocb.aio_return().unwrap() as usize, LEN);
++    /// }
++    /// assert_eq!(rbuf, b"cdef");
++    /// # }
++    /// ```
++    pub fn from_mut_slice(fd: RawFd, offs: off_t, buf: &'a mut [u8],
++                          prio: libc::c_int, sigev_notify: SigevNotify,
++                          opcode: LioOpcode) -> AioCb<'a> {
++        let mut a = AioCb::common_init(fd, prio, sigev_notify);
++        a.aio_offset = offs;
++        a.aio_nbytes = buf.len() as size_t;
++        a.aio_buf = buf.as_ptr() as *mut c_void;
++        a.aio_lio_opcode = opcode as libc::c_int;
++
++        AioCb {
++            aiocb: a,
++            mutable: true,
++            in_progress: false,
++            buffer: Buffer::Phantom(PhantomData),
++        }
++    }
++
++    /// The safest and most flexible way to create an `AioCb`.
++    ///
++    /// Unlike [`from_slice`], this method returns a structure suitable for
++    /// placement on the heap.  It may be used for write operations, but not
++    /// read operations.  Unlike `from_ptr`, this method will ensure that the
++    /// buffer doesn't `drop` while the kernel is still processing it.  Any
++    /// object that can be borrowed as a boxed slice will work.
++    ///
++    /// # Parameters
++    ///
++    /// * `fd`:           File descriptor.  Required for all aio functions.
++    /// * `offs`:         File offset
++    /// * `buf`:          A boxed slice-like object
++    /// * `prio`:         If POSIX Prioritized IO is supported, then the
++    ///                   operation will be prioritized at the process's
++    ///                   priority level minus `prio`
++    /// * `sigev_notify`: Determines how you will be notified of event
++    ///                   completion.
++    /// * `opcode`:       This field is only used for `lio_listio`.  It
++    ///                   determines which operation to use for this individual
++    ///                   aiocb
++    ///
++    /// # Examples
++    ///
++    /// Create an `AioCb` from a Vector and use it for writing
++    ///
++    /// ```
++    /// # extern crate tempfile;
++    /// # extern crate nix;
++    /// # use nix::errno::Errno;
++    /// # use nix::Error;
++    /// # use nix::sys::aio::*;
++    /// # use nix::sys::signal::SigevNotify;
++    /// # use std::{thread, time};
++    /// # use std::io::Write;
++    /// # use std::os::unix::io::AsRawFd;
++    /// # use tempfile::tempfile;
++    /// # fn main() {
++    /// let wbuf = Box::new(Vec::from("CDEF"));
++    /// let expected_len = wbuf.len();
++    /// let mut f = tempfile().unwrap();
++    /// let mut aiocb = AioCb::from_boxed_slice( f.as_raw_fd(),
++    ///     2,   //offset
++    ///     wbuf,
++    ///     0,   //priority
++    ///     SigevNotify::SigevNone,
++    ///     LioOpcode::LIO_NOP);
++    /// aiocb.write().unwrap();
++    /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
++    ///     thread::sleep(time::Duration::from_millis(10));
++    /// }
++    /// assert_eq!(aiocb.aio_return().unwrap() as usize, expected_len);
++    /// # }
++    /// ```
++    ///
++    /// Create an `AioCb` from a `Bytes` object
++    ///
++    /// ```
++    /// # extern crate bytes;
++    /// # extern crate tempfile;
++    /// # extern crate nix;
++    /// # use bytes::Bytes;
++    /// # use nix::sys::aio::*;
++    /// # use nix::sys::signal::SigevNotify;
++    /// # use std::os::unix::io::AsRawFd;
++    /// # use tempfile::tempfile;
++    /// # fn main() {
++    /// let wbuf = Box::new(Bytes::from(&b"CDEF"[..]));
++    /// let mut f = tempfile().unwrap();
++    /// let mut aiocb = AioCb::from_boxed_slice( f.as_raw_fd(),
++    ///     2,   //offset
++    ///     wbuf,
++    ///     0,   //priority
++    ///     SigevNotify::SigevNone,
++    ///     LioOpcode::LIO_NOP);
++    /// # }
++    /// ```
++    ///
++    /// If a library needs to work with buffers that aren't `Box`ed, it can
++    /// create a `Box`ed container for use with this method.  Here's an example
++    /// using an un`Box`ed `Bytes` object.
++    ///
++    /// ```
++    /// # extern crate bytes;
++    /// # extern crate tempfile;
++    /// # extern crate nix;
++    /// # use bytes::Bytes;
++    /// # use nix::sys::aio::*;
++    /// # use nix::sys::signal::SigevNotify;
++    /// # use std::borrow::Borrow;
++    /// # use std::os::unix::io::AsRawFd;
++    /// # use tempfile::tempfile;
++    /// struct BytesContainer(Bytes);
++    /// impl Borrow<[u8]> for BytesContainer {
++    ///     fn borrow(&self) -> &[u8] {
++    ///         self.0.as_ref()
++    ///     }
++    /// }
++    /// fn main() {
++    ///     let wbuf = Bytes::from(&b"CDEF"[..]);
++    ///     let boxed_wbuf = Box::new(BytesContainer(wbuf));
++    ///     let mut f = tempfile().unwrap();
++    ///     let mut aiocb = AioCb::from_boxed_slice( f.as_raw_fd(),
++    ///         2,   //offset
++    ///         boxed_wbuf,
++    ///         0,   //priority
++    ///         SigevNotify::SigevNone,
++    ///         LioOpcode::LIO_NOP);
++    /// }
++    /// ```
++    ///
++    /// [`from_slice`]: #method.from_slice
++    pub fn from_boxed_slice(fd: RawFd, offs: off_t, buf: Box<dyn Borrow<[u8]>>,
++                      prio: libc::c_int, sigev_notify: SigevNotify,
++                      opcode: LioOpcode) -> AioCb<'a> {
++        let mut a = AioCb::common_init(fd, prio, sigev_notify);
++        {
++            let borrowed : &dyn Borrow<[u8]> = buf.borrow();
++            let slice : &[u8] = borrowed.borrow();
++            a.aio_nbytes = slice.len() as size_t;
++            a.aio_buf = slice.as_ptr() as *mut c_void;
++        }
++        a.aio_offset = offs;
++        a.aio_lio_opcode = opcode as libc::c_int;
++
++        AioCb {
++            aiocb: a,
++            mutable: false,
++            in_progress: false,
++            buffer: Buffer::BoxedSlice(buf),
++        }
++    }
++
++    /// The safest and most flexible way to create an `AioCb` for reading.
++    ///
++    /// Like [`from_boxed_slice`], but the slice is a mutable one.  More
++    /// flexible than [`from_mut_slice`], because a wide range of objects can be
++    /// used.
++    ///
++    /// # Examples
++    ///
++    /// Create an `AioCb` from a Vector and use it for reading
++    ///
++    /// ```
++    /// # extern crate tempfile;
++    /// # extern crate nix;
++    /// # use nix::errno::Errno;
++    /// # use nix::Error;
++    /// # use nix::sys::aio::*;
++    /// # use nix::sys::signal::SigevNotify;
++    /// # use std::{thread, time};
++    /// # use std::io::Write;
++    /// # use std::os::unix::io::AsRawFd;
++    /// # use tempfile::tempfile;
++    /// # fn main() {
++    /// const INITIAL: &[u8] = b"abcdef123456";
++    /// const LEN: usize = 4;
++    /// let rbuf = Box::new(vec![0; LEN]);
++    /// let mut f = tempfile().unwrap();
++    /// f.write_all(INITIAL).unwrap();
++    /// let mut aiocb = AioCb::from_boxed_mut_slice( f.as_raw_fd(),
++    ///     2,   //offset
++    ///     rbuf,
++    ///     0,   //priority
++    ///     SigevNotify::SigevNone,
++    ///     LioOpcode::LIO_NOP);
++    /// aiocb.read().unwrap();
++    /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
++    ///     thread::sleep(time::Duration::from_millis(10));
++    /// }
++    /// assert_eq!(aiocb.aio_return().unwrap() as usize, LEN);
++    /// let mut buffer = aiocb.boxed_mut_slice().unwrap();
++    /// const EXPECT: &[u8] = b"cdef";
++    /// assert_eq!(buffer.borrow_mut(), EXPECT);
++    /// # }
++    /// ```
++    ///
++    /// [`from_boxed_slice`]: #method.from_boxed_slice
++    /// [`from_mut_slice`]: #method.from_mut_slice
++    pub fn from_boxed_mut_slice(fd: RawFd, offs: off_t,
++                                mut buf: Box<dyn BorrowMut<[u8]>>,
++                                prio: libc::c_int, sigev_notify: SigevNotify,
++                                opcode: LioOpcode) -> AioCb<'a> {
++        let mut a = AioCb::common_init(fd, prio, sigev_notify);
++        {
++            let borrowed : &mut dyn BorrowMut<[u8]> = buf.borrow_mut();
++            let slice : &mut [u8] = borrowed.borrow_mut();
++            a.aio_nbytes = slice.len() as size_t;
++            a.aio_buf = slice.as_mut_ptr() as *mut c_void;
++        }
++        a.aio_offset = offs;
++        a.aio_lio_opcode = opcode as libc::c_int;
++
++        AioCb {
++            aiocb: a,
++            mutable: true,
++            in_progress: false,
++            buffer: Buffer::BoxedMutSlice(buf),
++        }
++    }
++
++    /// Constructs a new `AioCb` from a mutable raw pointer
++    ///
++    /// Unlike `from_mut_slice`, this method returns a structure suitable for
++    /// placement on the heap.  It may be used for both reads and writes.  Due
++    /// to its unsafety, this method is not recommended.  It is most useful when
++    /// heap allocation is required but for some reason the data cannot be
++    /// wrapped in a `struct` that implements `BorrowMut<[u8]>`
++    ///
++    /// # Parameters
++    ///
++    /// * `fd`:           File descriptor.  Required for all aio functions.
++    /// * `offs`:         File offset
++    /// * `buf`:          Pointer to the memory buffer
++    /// * `len`:          Length of the buffer pointed to by `buf`
++    /// * `prio`:         If POSIX Prioritized IO is supported, then the
++    ///                   operation will be prioritized at the process's
++    ///                   priority level minus `prio`
++    /// * `sigev_notify`: Determines how you will be notified of event
++    ///                   completion.
++    /// * `opcode`:       This field is only used for `lio_listio`.  It
++    ///                   determines which operation to use for this individual
++    ///                   aiocb
++    ///
++    /// # Safety
++    ///
++    /// The caller must ensure that the storage pointed to by `buf` outlives the
++    /// `AioCb`.  The lifetime checker can't help here.
++    pub unsafe fn from_mut_ptr(fd: RawFd, offs: off_t,
++                           buf: *mut c_void, len: usize,
++                           prio: libc::c_int, sigev_notify: SigevNotify,
++                           opcode: LioOpcode) -> AioCb<'a> {
++        let mut a = AioCb::common_init(fd, prio, sigev_notify);
++        a.aio_offset = offs;
++        a.aio_nbytes = len;
++        a.aio_buf = buf;
++        a.aio_lio_opcode = opcode as libc::c_int;
++
++        AioCb {
++            aiocb: a,
++            mutable: true,
++            in_progress: false,
++            buffer: Buffer::None
++        }
++    }
++
++    /// Constructs a new `AioCb` from a raw pointer.
++    ///
++    /// Unlike `from_slice`, this method returns a structure suitable for
++    /// placement on the heap.  Due to its unsafety, this method is not
++    /// recommended.  It is most useful when heap allocation is required but for
++    /// some reason the data cannot be wrapped in a `struct` that implements
++    /// `Borrow<[u8]>`
++    ///
++    /// # Parameters
++    ///
++    /// * `fd`:           File descriptor.  Required for all aio functions.
++    /// * `offs`:         File offset
++    /// * `buf`:          Pointer to the memory buffer
++    /// * `len`:          Length of the buffer pointed to by `buf`
++    /// * `prio`:         If POSIX Prioritized IO is supported, then the
++    ///                   operation will be prioritized at the process's
++    ///                   priority level minus `prio`
++    /// * `sigev_notify`: Determines how you will be notified of event
++    ///                   completion.
++    /// * `opcode`:       This field is only used for `lio_listio`.  It
++    ///                   determines which operation to use for this individual
++    ///                   aiocb
++    ///
++    /// # Safety
++    ///
++    /// The caller must ensure that the storage pointed to by `buf` outlives the
++    /// `AioCb`.  The lifetime checker can't help here.
++    pub unsafe fn from_ptr(fd: RawFd, offs: off_t,
++                           buf: *const c_void, len: usize,
++                           prio: libc::c_int, sigev_notify: SigevNotify,
++                           opcode: LioOpcode) -> AioCb<'a> {
++        let mut a = AioCb::common_init(fd, prio, sigev_notify);
++        a.aio_offset = offs;
++        a.aio_nbytes = len;
++        // casting a const ptr to a mutable ptr here is ok, because we set the
++        // AioCb's mutable field to false
++        a.aio_buf = buf as *mut c_void;
++        a.aio_lio_opcode = opcode as libc::c_int;
++
++        AioCb {
++            aiocb: a,
++            mutable: false,
++            in_progress: false,
++            buffer: Buffer::None
++        }
++    }
++
++    /// Like `from_mut_slice`, but works on constant slices rather than
++    /// mutable slices.
++    ///
++    /// An `AioCb` created this way cannot be used with `read`, and its
++    /// `LioOpcode` cannot be set to `LIO_READ`.  This method is useful when
++    /// writing a const buffer with `AioCb::write`, since `from_mut_slice` can't
++    /// work with const buffers.
++    ///
++    /// # Examples
++    ///
++    /// Construct an `AioCb` from a slice and use it for writing.
++    ///
++    /// ```
++    /// # extern crate tempfile;
++    /// # extern crate nix;
++    /// # use nix::errno::Errno;
++    /// # use nix::Error;
++    /// # use nix::sys::aio::*;
++    /// # use nix::sys::signal::SigevNotify;
++    /// # use std::{thread, time};
++    /// # use std::os::unix::io::AsRawFd;
++    /// # use tempfile::tempfile;
++    /// # fn main() {
++    /// const WBUF: &[u8] = b"abcdef123456";
++    /// let mut f = tempfile().unwrap();
++    /// let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
++    ///     2,   //offset
++    ///     WBUF,
++    ///     0,   //priority
++    ///     SigevNotify::SigevNone,
++    ///     LioOpcode::LIO_NOP);
++    /// aiocb.write().unwrap();
++    /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
++    ///     thread::sleep(time::Duration::from_millis(10));
++    /// }
++    /// assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len());
++    /// # }
++    /// ```
++    // Note: another solution to the problem of writing const buffers would be
++    // to genericize AioCb for both &mut [u8] and &[u8] buffers.  AioCb::read
++    // could take the former and AioCb::write could take the latter.  However,
++    // then lio_listio wouldn't work, because that function needs a slice of
++    // AioCb, and they must all be of the same type.
++    pub fn from_slice(fd: RawFd, offs: off_t, buf: &'a [u8],
++                      prio: libc::c_int, sigev_notify: SigevNotify,
++                      opcode: LioOpcode) -> AioCb {
++        let mut a = AioCb::common_init(fd, prio, sigev_notify);
++        a.aio_offset = offs;
++        a.aio_nbytes = buf.len() as size_t;
++        // casting an immutable buffer to a mutable pointer looks unsafe,
++        // but technically its only unsafe to dereference it, not to create
++        // it.
++        a.aio_buf = buf.as_ptr() as *mut c_void;
++        assert!(opcode != LioOpcode::LIO_READ, "Can't read into an immutable buffer");
++        a.aio_lio_opcode = opcode as libc::c_int;
++
++        AioCb {
++            aiocb: a,
++            mutable: false,
++            in_progress: false,
++            buffer: Buffer::None,
++        }
++    }
++
++    fn common_init(fd: RawFd, prio: libc::c_int,
++                   sigev_notify: SigevNotify) -> libc::aiocb {
++        // Use mem::zeroed instead of explicitly zeroing each field, because the
++        // number and name of reserved fields is OS-dependent.  On some OSes,
++        // some reserved fields are used the kernel for state, and must be
++        // explicitly zeroed when allocated.
++        let mut a = unsafe { mem::zeroed::<libc::aiocb>()};
++        a.aio_fildes = fd;
++        a.aio_reqprio = prio;
++        a.aio_sigevent = SigEvent::new(sigev_notify).sigevent();
++        a
++    }
++
++    /// Update the notification settings for an existing `aiocb`
++    pub fn set_sigev_notify(&mut self, sigev_notify: SigevNotify) {
++        self.aiocb.aio_sigevent = SigEvent::new(sigev_notify).sigevent();
++    }
++
++    /// Cancels an outstanding AIO request.
++    ///
++    /// The operating system is not required to implement cancellation for all
++    /// file and device types.  Even if it does, there is no guarantee that the
++    /// operation has not already completed.  So the caller must check the
++    /// result and handle operations that were not canceled or that have already
++    /// completed.
++    ///
++    /// # Examples
++    ///
++    /// Cancel an outstanding aio operation.  Note that we must still call
++    /// `aio_return` to free resources, even though we don't care about the
++    /// result.
++    ///
++    /// ```
++    /// # extern crate tempfile;
++    /// # extern crate nix;
++    /// # use nix::errno::Errno;
++    /// # use nix::Error;
++    /// # use nix::sys::aio::*;
++    /// # use nix::sys::signal::SigevNotify;
++    /// # use std::{thread, time};
++    /// # use std::io::Write;
++    /// # use std::os::unix::io::AsRawFd;
++    /// # use tempfile::tempfile;
++    /// # fn main() {
++    /// let wbuf = b"CDEF";
++    /// let mut f = tempfile().unwrap();
++    /// let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
++    ///     2,   //offset
++    ///     &wbuf[..],
++    ///     0,   //priority
++    ///     SigevNotify::SigevNone,
++    ///     LioOpcode::LIO_NOP);
++    /// aiocb.write().unwrap();
++    /// let cs = aiocb.cancel().unwrap();
++    /// if cs == AioCancelStat::AioNotCanceled {
++    ///     while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
++    ///         thread::sleep(time::Duration::from_millis(10));
++    ///     }
++    /// }
++    /// // Must call `aio_return`, but ignore the result
++    /// let _ = aiocb.aio_return();
++    /// # }
++    /// ```
++    ///
++    /// # References
++    ///
++    /// [aio_cancel](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html)
++    pub fn cancel(&mut self) -> Result<AioCancelStat> {
++        match unsafe { libc::aio_cancel(self.aiocb.aio_fildes, &mut self.aiocb) } {
++            libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled),
++            libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled),
++            libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone),
++            -1 => Err(Error::last()),
++            _ => panic!("unknown aio_cancel return value")
++        }
++    }
++
++    /// Retrieve error status of an asynchronous operation.
++    ///
++    /// If the request has not yet completed, returns `EINPROGRESS`.  Otherwise,
++    /// returns `Ok` or any other error.
++    ///
++    /// # Examples
++    ///
++    /// Issue an aio operation and use `error` to poll for completion.  Polling
++    /// is an alternative to `aio_suspend`, used by most of the other examples.
++    ///
++    /// ```
++    /// # extern crate tempfile;
++    /// # extern crate nix;
++    /// # use nix::errno::Errno;
++    /// # use nix::Error;
++    /// # use nix::sys::aio::*;
++    /// # use nix::sys::signal::SigevNotify;
++    /// # use std::{thread, time};
++    /// # use std::os::unix::io::AsRawFd;
++    /// # use tempfile::tempfile;
++    /// # fn main() {
++    /// const WBUF: &[u8] = b"abcdef123456";
++    /// let mut f = tempfile().unwrap();
++    /// let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
++    ///     2,   //offset
++    ///     WBUF,
++    ///     0,   //priority
++    ///     SigevNotify::SigevNone,
++    ///     LioOpcode::LIO_NOP);
++    /// aiocb.write().unwrap();
++    /// while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
++    ///     thread::sleep(time::Duration::from_millis(10));
++    /// }
++    /// assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len());
++    /// # }
++    /// ```
++    ///
++    /// # References
++    ///
++    /// [aio_error](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_error.html)
++    pub fn error(&mut self) -> Result<()> {
++        match unsafe { libc::aio_error(&mut self.aiocb as *mut libc::aiocb) } {
++            0 => Ok(()),
++            num if num > 0 => Err(Error::from_errno(Errno::from_i32(num))),
++            -1 => Err(Error::last()),
++            num => panic!("unknown aio_error return value {:?}", num)
++        }
++    }
++
++    /// An asynchronous version of `fsync(2)`.
++    ///
++    /// # References
++    ///
++    /// [aio_fsync](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_fsync.html)
++    pub fn fsync(&mut self, mode: AioFsyncMode) -> Result<()> {
++        let p: *mut libc::aiocb = &mut self.aiocb;
++        Errno::result(unsafe {
++                libc::aio_fsync(mode as libc::c_int, p)
++        }).map(|_| {
++            self.in_progress = true;
++        })
++    }
++
++    /// Returns the `aiocb`'s `LioOpcode` field
++    ///
++    /// If the value cannot be represented as an `LioOpcode`, returns `None`
++    /// instead.
++    pub fn lio_opcode(&self) -> Option<LioOpcode> {
++        match self.aiocb.aio_lio_opcode {
++            libc::LIO_READ => Some(LioOpcode::LIO_READ),
++            libc::LIO_WRITE => Some(LioOpcode::LIO_WRITE),
++            libc::LIO_NOP => Some(LioOpcode::LIO_NOP),
++            _ => None
++        }
++    }
++
++    /// Returns the requested length of the aio operation in bytes
++    ///
++    /// This method returns the *requested* length of the operation.  To get the
++    /// number of bytes actually read or written by a completed operation, use
++    /// `aio_return` instead.
++    pub fn nbytes(&self) -> usize {
++        self.aiocb.aio_nbytes
++    }
++
++    /// Returns the file offset stored in the `AioCb`
++    pub fn offset(&self) -> off_t {
++        self.aiocb.aio_offset
++    }
++
++    /// Returns the priority of the `AioCb`
++    pub fn priority(&self) -> libc::c_int {
++        self.aiocb.aio_reqprio
++    }
++
++    /// Asynchronously reads from a file descriptor into a buffer
++    ///
++    /// # References
++    ///
++    /// [aio_read](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_read.html)
++    pub fn read(&mut self) -> Result<()> {
++        assert!(self.mutable, "Can't read into an immutable buffer");
++        let p: *mut libc::aiocb = &mut self.aiocb;
++        Errno::result(unsafe {
++            libc::aio_read(p)
++        }).map(|_| {
++            self.in_progress = true;
++        })
++    }
++
++    /// Returns the `SigEvent` stored in the `AioCb`
++    pub fn sigevent(&self) -> SigEvent {
++        SigEvent::from(&self.aiocb.aio_sigevent)
++    }
++
++    /// Retrieve return status of an asynchronous operation.
++    ///
++    /// Should only be called once for each `AioCb`, after `AioCb::error`
++    /// indicates that it has completed.  The result is the same as for the
++    /// synchronous `read(2)`, `write(2)`, of `fsync(2)` functions.
++    ///
++    /// # References
++    ///
++    /// [aio_return](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_return.html)
++    // Note: this should be just `return`, but that's a reserved word
++    pub fn aio_return(&mut self) -> Result<isize> {
++        let p: *mut libc::aiocb = &mut self.aiocb;
++        self.in_progress = false;
++        Errno::result(unsafe { libc::aio_return(p) })
++    }
++
++    /// Asynchronously writes from a buffer to a file descriptor
++    ///
++    /// # References
++    ///
++    /// [aio_write](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_write.html)
++    pub fn write(&mut self) -> Result<()> {
++        let p: *mut libc::aiocb = &mut self.aiocb;
++        Errno::result(unsafe {
++            libc::aio_write(p)
++        }).map(|_| {
++            self.in_progress = true;
++        })
++    }
++
++}
++
++/// Cancels outstanding AIO requests for a given file descriptor.
++///
++/// # Examples
++///
++/// Issue an aio operation, then cancel all outstanding operations on that file
++/// descriptor.
++///
++/// ```
++/// # extern crate tempfile;
++/// # extern crate nix;
++/// # use nix::errno::Errno;
++/// # use nix::Error;
++/// # use nix::sys::aio::*;
++/// # use nix::sys::signal::SigevNotify;
++/// # use std::{thread, time};
++/// # use std::io::Write;
++/// # use std::os::unix::io::AsRawFd;
++/// # use tempfile::tempfile;
++/// # fn main() {
++/// let wbuf = b"CDEF";
++/// let mut f = tempfile().unwrap();
++/// let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
++///     2,   //offset
++///     &wbuf[..],
++///     0,   //priority
++///     SigevNotify::SigevNone,
++///     LioOpcode::LIO_NOP);
++/// aiocb.write().unwrap();
++/// let cs = aio_cancel_all(f.as_raw_fd()).unwrap();
++/// if cs == AioCancelStat::AioNotCanceled {
++///     while (aiocb.error() == Err(Error::from(Errno::EINPROGRESS))) {
++///         thread::sleep(time::Duration::from_millis(10));
++///     }
++/// }
++/// // Must call `aio_return`, but ignore the result
++/// let _ = aiocb.aio_return();
++/// # }
++/// ```
++///
++/// # References
++///
++/// [`aio_cancel`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_cancel.html)
++pub fn aio_cancel_all(fd: RawFd) -> Result<AioCancelStat> {
++    match unsafe { libc::aio_cancel(fd, null_mut()) } {
++        libc::AIO_CANCELED => Ok(AioCancelStat::AioCanceled),
++        libc::AIO_NOTCANCELED => Ok(AioCancelStat::AioNotCanceled),
++        libc::AIO_ALLDONE => Ok(AioCancelStat::AioAllDone),
++        -1 => Err(Error::last()),
++        _ => panic!("unknown aio_cancel return value")
++    }
++}
++
++/// Suspends the calling process until at least one of the specified `AioCb`s
++/// has completed, a signal is delivered, or the timeout has passed.
++///
++/// If `timeout` is `None`, `aio_suspend` will block indefinitely.
++///
++/// # Examples
++///
++/// Use `aio_suspend` to block until an aio operation completes.
++///
++// Disable doctest due to a known bug in FreeBSD's 32-bit emulation.  The fix
++// will be included in release 11.2.
++// FIXME reenable the doc test when the CI machine gets upgraded to that release.
++// https://svnweb.freebsd.org/base?view=revision&revision=325018
++/// ```no_run
++/// # extern crate tempfile;
++/// # extern crate nix;
++/// # use nix::sys::aio::*;
++/// # use nix::sys::signal::SigevNotify;
++/// # use std::os::unix::io::AsRawFd;
++/// # use tempfile::tempfile;
++/// # fn main() {
++/// const WBUF: &[u8] = b"abcdef123456";
++/// let mut f = tempfile().unwrap();
++/// let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
++///     2,   //offset
++///     WBUF,
++///     0,   //priority
++///     SigevNotify::SigevNone,
++///     LioOpcode::LIO_NOP);
++/// aiocb.write().unwrap();
++/// aio_suspend(&[&aiocb], None).expect("aio_suspend failed");
++/// assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len());
++/// # }
++/// ```
++/// # References
++///
++/// [`aio_suspend`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/aio_suspend.html)
++pub fn aio_suspend(list: &[&AioCb], timeout: Option<TimeSpec>) -> Result<()> {
++    let plist = list as *const [&AioCb] as *const [*const libc::aiocb];
++    let p = plist as *const *const libc::aiocb;
++    let timep = match timeout {
++        None    => null::<libc::timespec>(),
++        Some(x) => x.as_ref() as *const libc::timespec
++    };
++    Errno::result(unsafe {
++        libc::aio_suspend(p, list.len() as i32, timep)
++    }).map(drop)
++}
++
++impl<'a> Debug for AioCb<'a> {
++    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
++        fmt.debug_struct("AioCb")
++            .field("aiocb", &self.aiocb)
++            .field("mutable", &self.mutable)
++            .field("in_progress", &self.in_progress)
++            .finish()
++    }
++}
++
++impl<'a> Drop for AioCb<'a> {
++    /// If the `AioCb` has no remaining state in the kernel, just drop it.
++    /// Otherwise, dropping constitutes a resource leak, which is an error
++    fn drop(&mut self) {
++        assert!(thread::panicking() || !self.in_progress,
++                "Dropped an in-progress AioCb");
++    }
++}
++
++/// LIO Control Block.
++///
++/// The basic structure used to issue multiple AIO operations simultaneously.
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++pub struct LioCb<'a> {
++    /// A collection of [`AioCb`]s.  All of these will be issued simultaneously
++    /// by the [`listio`] method.
++    ///
++    /// [`AioCb`]: struct.AioCb.html
++    /// [`listio`]: #method.listio
++    pub aiocbs: Vec<AioCb<'a>>,
++
++    /// The actual list passed to `libc::lio_listio`.
++    ///
++    /// It must live for as long as any of the operations are still being
++    /// processesed, because the aio subsystem uses its address as a unique
++    /// identifier.
++    list: Vec<*mut libc::aiocb>,
++
++    /// A partial set of results.  This field will get populated by
++    /// `listio_resubmit` when an `LioCb` is resubmitted after an error
++    results: Vec<Option<Result<isize>>>
++}
++
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++impl<'a> LioCb<'a> {
++    /// Initialize an empty `LioCb`
++    pub fn with_capacity(capacity: usize) -> LioCb<'a> {
++        LioCb {
++            aiocbs: Vec::with_capacity(capacity),
++            list: Vec::with_capacity(capacity),
++            results: Vec::with_capacity(capacity)
++        }
++    }
++
++    /// Submits multiple asynchronous I/O requests with a single system call.
++    ///
++    /// They are not guaranteed to complete atomically, and the order in which
++    /// the requests are carried out is not specified.  Reads, writes, and
++    /// fsyncs may be freely mixed.
++    ///
++    /// This function is useful for reducing the context-switch overhead of
++    /// submitting many AIO operations.  It can also be used with
++    /// `LioMode::LIO_WAIT` to block on the result of several independent
++    /// operations.  Used that way, it is often useful in programs that
++    /// otherwise make little use of AIO.
++    ///
++    /// # Examples
++    ///
++    /// Use `listio` to submit an aio operation and wait for its completion.  In
++    /// this case, there is no need to use [`aio_suspend`] to wait or
++    /// [`AioCb::error`] to poll.
++    ///
++    /// ```
++    /// # extern crate tempfile;
++    /// # extern crate nix;
++    /// # use nix::sys::aio::*;
++    /// # use nix::sys::signal::SigevNotify;
++    /// # use std::os::unix::io::AsRawFd;
++    /// # use tempfile::tempfile;
++    /// # fn main() {
++    /// const WBUF: &[u8] = b"abcdef123456";
++    /// let mut f = tempfile().unwrap();
++    /// let mut liocb = LioCb::with_capacity(1);
++    /// liocb.aiocbs.push(AioCb::from_slice( f.as_raw_fd(),
++    ///     2,   //offset
++    ///     WBUF,
++    ///     0,   //priority
++    ///     SigevNotify::SigevNone,
++    ///     LioOpcode::LIO_WRITE));
++    /// liocb.listio(LioMode::LIO_WAIT,
++    ///              SigevNotify::SigevNone).unwrap();
++    /// assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len());
++    /// # }
++    /// ```
++    ///
++    /// # References
++    ///
++    /// [`lio_listio`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lio_listio.html)
++    ///
++    /// [`aio_suspend`]: fn.aio_suspend.html
++    /// [`AioCb::error`]: struct.AioCb.html#method.error
++    pub fn listio(&mut self, mode: LioMode,
++                  sigev_notify: SigevNotify) -> Result<()> {
++        let sigev = SigEvent::new(sigev_notify);
++        let sigevp = &mut sigev.sigevent() as *mut libc::sigevent;
++        self.list.clear();
++        for a in &mut self.aiocbs {
++            a.in_progress = true;
++            self.list.push(a as *mut AioCb<'a>
++                             as *mut libc::aiocb);
++        }
++        let p = self.list.as_ptr();
++        Errno::result(unsafe {
++            libc::lio_listio(mode as i32, p, self.list.len() as i32, sigevp)
++        }).map(drop)
++    }
++
++    /// Resubmits any incomplete operations with [`lio_listio`].
++    ///
++    /// Sometimes, due to system resource limitations, an `lio_listio` call will
++    /// return `EIO`, or `EAGAIN`.  Or, if a signal is received, it may return
++    /// `EINTR`.  In any of these cases, only a subset of its constituent
++    /// operations will actually have been initiated.  `listio_resubmit` will
++    /// resubmit any operations that are still uninitiated.
++    ///
++    /// After calling `listio_resubmit`, results should be collected by
++    /// [`LioCb::aio_return`].
++    ///
++    /// # Examples
++    /// ```no_run
++    /// # extern crate tempfile;
++    /// # extern crate nix;
++    /// # use nix::Error;
++    /// # use nix::errno::Errno;
++    /// # use nix::sys::aio::*;
++    /// # use nix::sys::signal::SigevNotify;
++    /// # use std::os::unix::io::AsRawFd;
++    /// # use std::{thread, time};
++    /// # use tempfile::tempfile;
++    /// # fn main() {
++    /// const WBUF: &[u8] = b"abcdef123456";
++    /// let mut f = tempfile().unwrap();
++    /// let mut liocb = LioCb::with_capacity(1);
++    /// liocb.aiocbs.push(AioCb::from_slice( f.as_raw_fd(),
++    ///     2,   //offset
++    ///     WBUF,
++    ///     0,   //priority
++    ///     SigevNotify::SigevNone,
++    ///     LioOpcode::LIO_WRITE));
++    /// let mut err = liocb.listio(LioMode::LIO_WAIT, SigevNotify::SigevNone);
++    /// while err == Err(Error::Sys(Errno::EIO)) ||
++    ///       err == Err(Error::Sys(Errno::EAGAIN)) {
++    ///     thread::sleep(time::Duration::from_millis(10));
++    ///     err = liocb.listio_resubmit(LioMode::LIO_WAIT, SigevNotify::SigevNone);
++    /// }
++    /// assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len());
++    /// # }
++    /// ```
++    ///
++    /// # References
++    ///
++    /// [`lio_listio`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lio_listio.html)
++    ///
++    /// [`lio_listio`]: http://pubs.opengroup.org/onlinepubs/9699919799/functions/lio_listio.html
++    /// [`LioCb::aio_return`]: struct.LioCb.html#method.aio_return
++    // Note: the addresses of any EINPROGRESS or EOK aiocbs _must_ not be
++    // changed by this method, because the kernel relies on their addresses
++    // being stable.
++    // Note: aiocbs that are Ok(()) must be finalized by aio_return, or else the
++    // sigev_notify will immediately refire.
++    pub fn listio_resubmit(&mut self, mode:LioMode,
++                           sigev_notify: SigevNotify) -> Result<()> {
++        let sigev = SigEvent::new(sigev_notify);
++        let sigevp = &mut sigev.sigevent() as *mut libc::sigevent;
++        self.list.clear();
++
++        while self.results.len() < self.aiocbs.len() {
++            self.results.push(None);
++        }
++
++        for (i, a) in self.aiocbs.iter_mut().enumerate() {
++            if self.results[i].is_some() {
++                // Already collected final status for this operation
++                continue;
++            }
++            match a.error() {
++                Ok(()) => {
++                    // aiocb is complete; collect its status and don't resubmit
++                    self.results[i] = Some(a.aio_return());
++                },
++                Err(Error::Sys(Errno::EAGAIN)) => {
++                    self.list.push(a as *mut AioCb<'a> as *mut libc::aiocb);
++                },
++                Err(Error::Sys(Errno::EINPROGRESS)) => {
++                    // aiocb is was successfully queued; no need to do anything
++                    ()
++                },
++                Err(Error::Sys(Errno::EINVAL)) => panic!(
++                    "AioCb was never submitted, or already finalized"),
++                _ => unreachable!()
++            }
++        }
++        let p = self.list.as_ptr();
++        Errno::result(unsafe {
++            libc::lio_listio(mode as i32, p, self.list.len() as i32, sigevp)
++        }).map(drop)
++    }
++
++    /// Collect final status for an individual `AioCb` submitted as part of an
++    /// `LioCb`.
++    ///
++    /// This is just like [`AioCb::aio_return`], except it takes into account
++    /// operations that were restarted by [`LioCb::listio_resubmit`]
++    ///
++    /// [`AioCb::aio_return`]: struct.AioCb.html#method.aio_return
++    /// [`LioCb::listio_resubmit`]: #method.listio_resubmit
++    pub fn aio_return(&mut self, i: usize) -> Result<isize> {
++        if i >= self.results.len() || self.results[i].is_none() {
++            self.aiocbs[i].aio_return()
++        } else {
++            self.results[i].unwrap()
++        }
++    }
++
++    /// Retrieve error status of an individual `AioCb` submitted as part of an
++    /// `LioCb`.
++    ///
++    /// This is just like [`AioCb::error`], except it takes into account
++    /// operations that were restarted by [`LioCb::listio_resubmit`]
++    ///
++    /// [`AioCb::error`]: struct.AioCb.html#method.error
++    /// [`LioCb::listio_resubmit`]: #method.listio_resubmit
++    pub fn error(&mut self, i: usize) -> Result<()> {
++        if i >= self.results.len() || self.results[i].is_none() {
++            self.aiocbs[i].error()
++        } else {
++            Ok(())
++        }
++    }
++}
++
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++impl<'a> Debug for LioCb<'a> {
++    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
++        fmt.debug_struct("LioCb")
++            .field("aiocbs", &self.aiocbs)
++            .finish()
++    }
++}
++
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++impl<'a> From<Vec<AioCb<'a>>> for LioCb<'a> {
++    fn from(src: Vec<AioCb<'a>>) -> LioCb<'a> {
++        LioCb {
++            list: Vec::with_capacity(src.capacity()),
++            results: Vec::with_capacity(src.capacity()),
++            aiocbs: src,
++        }
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/epoll.rs b/third_party/rust/nix-0.15.0/src/sys/epoll.rs
+new file mode 100644
+index 0000000000000..fef6f4e3ec92c
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/epoll.rs
+@@ -0,0 +1,109 @@
++use Result;
++use errno::Errno;
++use libc::{self, c_int};
++use std::os::unix::io::RawFd;
++use std::ptr;
++use std::mem;
++use ::Error;
++
++libc_bitflags!(
++    pub struct EpollFlags: c_int {
++        EPOLLIN;
++        EPOLLPRI;
++        EPOLLOUT;
++        EPOLLRDNORM;
++        EPOLLRDBAND;
++        EPOLLWRNORM;
++        EPOLLWRBAND;
++        EPOLLMSG;
++        EPOLLERR;
++        EPOLLHUP;
++        EPOLLRDHUP;
++        #[cfg(target_os = "linux")]  // Added in 4.5; not in Android.
++        EPOLLEXCLUSIVE;
++        #[cfg(not(target_arch = "mips"))]
++        EPOLLWAKEUP;
++        EPOLLONESHOT;
++        EPOLLET;
++    }
++);
++
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++#[repr(i32)]
++pub enum EpollOp {
++    EpollCtlAdd = libc::EPOLL_CTL_ADD,
++    EpollCtlDel = libc::EPOLL_CTL_DEL,
++    EpollCtlMod = libc::EPOLL_CTL_MOD,
++}
++
++libc_bitflags!{
++    pub struct EpollCreateFlags: c_int {
++        EPOLL_CLOEXEC;
++    }
++}
++
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++#[repr(C)]
++pub struct EpollEvent {
++    event: libc::epoll_event,
++}
++
++impl EpollEvent {
++    pub fn new(events: EpollFlags, data: u64) -> Self {
++        EpollEvent { event: libc::epoll_event { events: events.bits() as u32, u64: data } }
++    }
++
++    pub fn empty() -> Self {
++        unsafe { mem::zeroed::<EpollEvent>() }
++    }
++
++    pub fn events(&self) -> EpollFlags {
++        EpollFlags::from_bits(self.event.events as c_int).unwrap()
++    }
++
++    pub fn data(&self) -> u64 {
++        self.event.u64
++    }
++}
++
++#[inline]
++pub fn epoll_create() -> Result<RawFd> {
++    let res = unsafe { libc::epoll_create(1024) };
++
++    Errno::result(res)
++}
++
++#[inline]
++pub fn epoll_create1(flags: EpollCreateFlags) -> Result<RawFd> {
++    let res = unsafe { libc::epoll_create1(flags.bits()) };
++
++    Errno::result(res)
++}
++
++#[inline]
++pub fn epoll_ctl<'a, T>(epfd: RawFd, op: EpollOp, fd: RawFd, event: T) -> Result<()>
++    where T: Into<Option<&'a mut EpollEvent>>
++{
++    let mut event: Option<&mut EpollEvent> = event.into();
++    if event.is_none() && op != EpollOp::EpollCtlDel {
++        Err(Error::Sys(Errno::EINVAL))
++    } else {
++        let res = unsafe {
++            if let Some(ref mut event) = event {
++                libc::epoll_ctl(epfd, op as c_int, fd, &mut event.event)
++            } else {
++                libc::epoll_ctl(epfd, op as c_int, fd, ptr::null_mut())
++            }
++        };
++        Errno::result(res).map(drop)
++    }
++}
++
++#[inline]
++pub fn epoll_wait(epfd: RawFd, events: &mut [EpollEvent], timeout_ms: isize) -> Result<usize> {
++    let res = unsafe {
++        libc::epoll_wait(epfd, events.as_mut_ptr() as *mut libc::epoll_event, events.len() as c_int, timeout_ms as c_int)
++    };
++
++    Errno::result(res).map(|r| r as usize)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/event.rs b/third_party/rust/nix-0.15.0/src/sys/event.rs
+new file mode 100644
+index 0000000000000..8cd7372f88188
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/event.rs
+@@ -0,0 +1,351 @@
++/* TOOD: Implement for other kqueue based systems
++ */
++
++use {Errno, Result};
++#[cfg(not(target_os = "netbsd"))]
++use libc::{timespec, time_t, c_int, c_long, intptr_t, uintptr_t};
++#[cfg(target_os = "netbsd")]
++use libc::{timespec, time_t, c_long, intptr_t, uintptr_t, size_t};
++use libc;
++use std::os::unix::io::RawFd;
++use std::ptr;
++use std::mem;
++
++// Redefine kevent in terms of programmer-friendly enums and bitfields.
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct KEvent {
++    kevent: libc::kevent,
++}
++
++#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
++          target_os = "ios", target_os = "macos",
++          target_os = "openbsd"))]
++type type_of_udata = *mut libc::c_void;
++#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
++          target_os = "ios", target_os = "macos"))]
++type type_of_data = intptr_t;
++#[cfg(any(target_os = "netbsd"))]
++type type_of_udata = intptr_t;
++#[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
++type type_of_data = libc::int64_t;
++
++#[cfg(target_os = "netbsd")]
++type type_of_event_filter = u32;
++#[cfg(not(target_os = "netbsd"))]
++type type_of_event_filter = i16;
++libc_enum! {
++    #[cfg_attr(target_os = "netbsd", repr(u32))]
++    #[cfg_attr(not(target_os = "netbsd"), repr(i16))]
++    pub enum EventFilter {
++        EVFILT_AIO,
++        /// Returns whenever there is no remaining data in the write buffer
++        #[cfg(target_os = "freebsd")]
++        EVFILT_EMPTY,
++        #[cfg(target_os = "dragonfly")]
++        EVFILT_EXCEPT,
++        #[cfg(any(target_os = "dragonfly",
++                  target_os = "freebsd",
++                  target_os = "ios",
++                  target_os = "macos"))]
++        EVFILT_FS,
++        #[cfg(target_os = "freebsd")]
++        EVFILT_LIO,
++        #[cfg(any(target_os = "ios", target_os = "macos"))]
++        EVFILT_MACHPORT,
++        EVFILT_PROC,
++        /// Returns events associated with the process referenced by a given
++        /// process descriptor, created by `pdfork()`. The events to monitor are:
++        ///
++        /// - NOTE_EXIT: the process has exited. The exit status will be stored in data.
++        #[cfg(target_os = "freebsd")]
++        EVFILT_PROCDESC,
++        EVFILT_READ,
++        /// Returns whenever an asynchronous `sendfile()` call completes.
++        #[cfg(target_os = "freebsd")]
++        EVFILT_SENDFILE,
++        EVFILT_SIGNAL,
++        EVFILT_TIMER,
++        #[cfg(any(target_os = "dragonfly",
++                  target_os = "freebsd",
++                  target_os = "ios",
++                  target_os = "macos"))]
++        EVFILT_USER,
++        #[cfg(any(target_os = "ios", target_os = "macos"))]
++        EVFILT_VM,
++        EVFILT_VNODE,
++        EVFILT_WRITE,
++    }
++}
++
++#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
++          target_os = "ios", target_os = "macos",
++          target_os = "openbsd"))]
++pub type type_of_event_flag = u16;
++#[cfg(any(target_os = "netbsd"))]
++pub type type_of_event_flag = u32;
++libc_bitflags!{
++    pub struct EventFlag: type_of_event_flag {
++        EV_ADD;
++        EV_CLEAR;
++        EV_DELETE;
++        EV_DISABLE;
++        // No released version of OpenBSD supports EV_DISPATCH or EV_RECEIPT.
++        // These have been commited to the -current branch though and are
++        // expected to be part of the OpenBSD 6.2 release in Nov 2017.
++        // See: https://marc.info/?l=openbsd-tech&m=149621427511219&w=2
++        // https://github.com/rust-lang/libc/pull/613
++        #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
++                  target_os = "ios", target_os = "macos",
++                  target_os = "netbsd"))]
++        EV_DISPATCH;
++        #[cfg(target_os = "freebsd")]
++        EV_DROP;
++        EV_ENABLE;
++        EV_EOF;
++        EV_ERROR;
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        EV_FLAG0;
++        EV_FLAG1;
++        #[cfg(target_os = "dragonfly")]
++        EV_NODATA;
++        EV_ONESHOT;
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        EV_OOBAND;
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        EV_POLL;
++        #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
++                  target_os = "ios", target_os = "macos",
++                  target_os = "netbsd"))]
++        EV_RECEIPT;
++        EV_SYSFLAGS;
++    }
++}
++
++libc_bitflags!(
++    pub struct FilterFlag: u32 {
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        NOTE_ABSOLUTE;
++        NOTE_ATTRIB;
++        NOTE_CHILD;
++        NOTE_DELETE;
++        #[cfg(target_os = "openbsd")]
++        NOTE_EOF;
++        NOTE_EXEC;
++        NOTE_EXIT;
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        #[deprecated( since="0.14.0", note="Deprecated since OSX 10.9")]
++        #[allow(deprecated)]
++        NOTE_EXIT_REPARENTED;
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        NOTE_EXITSTATUS;
++        NOTE_EXTEND;
++        #[cfg(any(target_os = "macos",
++                  target_os = "ios",
++                  target_os = "freebsd",
++                  target_os = "dragonfly"))]
++        NOTE_FFAND;
++        #[cfg(any(target_os = "macos",
++                  target_os = "ios",
++                  target_os = "freebsd",
++                  target_os = "dragonfly"))]
++        NOTE_FFCOPY;
++        #[cfg(any(target_os = "macos",
++                  target_os = "ios",
++                  target_os = "freebsd",
++                  target_os = "dragonfly"))]
++        NOTE_FFCTRLMASK;
++        #[cfg(any(target_os = "macos",
++                  target_os = "ios",
++                  target_os = "freebsd",
++                  target_os = "dragonfly"))]
++        NOTE_FFLAGSMASK;
++        #[cfg(any(target_os = "macos",
++                  target_os = "ios",
++                  target_os = "freebsd",
++                  target_os = "dragonfly"))]
++        NOTE_FFNOP;
++        #[cfg(any(target_os = "macos",
++                  target_os = "ios",
++                  target_os = "freebsd",
++                  target_os = "dragonfly"))]
++        NOTE_FFOR;
++        NOTE_FORK;
++        NOTE_LINK;
++        NOTE_LOWAT;
++        #[cfg(target_os = "freebsd")]
++        NOTE_MSECONDS;
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        NOTE_NONE;
++        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
++        NOTE_NSECONDS;
++        #[cfg(target_os = "dragonfly")]
++        NOTE_OOB;
++        NOTE_PCTRLMASK;
++        NOTE_PDATAMASK;
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        #[deprecated( since="0.14.0", note="Deprecated since OSX 10.9")]
++        #[allow(deprecated)]
++        NOTE_REAP;
++        NOTE_RENAME;
++        NOTE_REVOKE;
++        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
++        NOTE_SECONDS;
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        NOTE_SIGNAL;
++        NOTE_TRACK;
++        NOTE_TRACKERR;
++        #[cfg(any(target_os = "macos",
++                  target_os = "ios",
++                  target_os = "freebsd",
++                  target_os = "dragonfly"))]
++        NOTE_TRIGGER;
++        #[cfg(target_os = "openbsd")]
++        NOTE_TRUNCATE;
++        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
++        NOTE_USECONDS;
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        NOTE_VM_ERROR;
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        NOTE_VM_PRESSURE;
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        NOTE_VM_PRESSURE_SUDDEN_TERMINATE;
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        NOTE_VM_PRESSURE_TERMINATE;
++        NOTE_WRITE;
++    }
++);
++
++pub fn kqueue() -> Result<RawFd> {
++    let res = unsafe { libc::kqueue() };
++
++    Errno::result(res)
++}
++
++
++// KEvent can't derive Send because on some operating systems, udata is defined
++// as a void*.  However, KEvent's public API always treats udata as an intptr_t,
++// which is safe to Send.
++unsafe impl Send for KEvent {
++}
++
++impl KEvent {
++    pub fn new(ident: uintptr_t, filter: EventFilter, flags: EventFlag,
++               fflags:FilterFlag, data: intptr_t, udata: intptr_t) -> KEvent {
++        KEvent { kevent: libc::kevent {
++            ident: ident,
++            filter: filter as type_of_event_filter,
++            flags: flags.bits(),
++            fflags: fflags.bits(),
++            data: data as type_of_data,
++            udata: udata as type_of_udata
++        } }
++    }
++
++    pub fn ident(&self) -> uintptr_t {
++        self.kevent.ident
++    }
++
++    pub fn filter(&self) -> EventFilter {
++        unsafe { mem::transmute(self.kevent.filter as type_of_event_filter) }
++    }
++
++    pub fn flags(&self) -> EventFlag {
++        EventFlag::from_bits(self.kevent.flags).unwrap()
++    }
++
++    pub fn fflags(&self) -> FilterFlag {
++        FilterFlag::from_bits(self.kevent.fflags).unwrap()
++    }
++
++    pub fn data(&self) -> intptr_t {
++        self.kevent.data as intptr_t
++    }
++
++    pub fn udata(&self) -> intptr_t {
++        self.kevent.udata as intptr_t
++    }
++}
++
++pub fn kevent(kq: RawFd,
++              changelist: &[KEvent],
++              eventlist: &mut [KEvent],
++              timeout_ms: usize) -> Result<usize> {
++
++    // Convert ms to timespec
++    let timeout = timespec {
++        tv_sec: (timeout_ms / 1000) as time_t,
++        tv_nsec: ((timeout_ms % 1000) * 1_000_000) as c_long
++    };
++
++    kevent_ts(kq, changelist, eventlist, Some(timeout))
++}
++
++#[cfg(any(target_os = "macos",
++          target_os = "ios",
++          target_os = "freebsd",
++          target_os = "dragonfly",
++          target_os = "openbsd"))]
++type type_of_nchanges = c_int;
++#[cfg(target_os = "netbsd")]
++type type_of_nchanges = size_t;
++
++pub fn kevent_ts(kq: RawFd,
++              changelist: &[KEvent],
++              eventlist: &mut [KEvent],
++              timeout_opt: Option<timespec>) -> Result<usize> {
++
++    let res = unsafe {
++        libc::kevent(
++            kq,
++            changelist.as_ptr() as *const libc::kevent,
++            changelist.len() as type_of_nchanges,
++            eventlist.as_mut_ptr() as *mut libc::kevent,
++            eventlist.len() as type_of_nchanges,
++            if let Some(ref timeout) = timeout_opt {timeout as *const timespec} else {ptr::null()})
++    };
++
++    Errno::result(res).map(|r| r as usize)
++}
++
++#[inline]
++pub fn ev_set(ev: &mut KEvent,
++              ident: usize,
++              filter: EventFilter,
++              flags: EventFlag,
++              fflags: FilterFlag,
++              udata: intptr_t) {
++
++    ev.kevent.ident  = ident as uintptr_t;
++    ev.kevent.filter = filter as type_of_event_filter;
++    ev.kevent.flags  = flags.bits();
++    ev.kevent.fflags = fflags.bits();
++    ev.kevent.data   = 0;
++    ev.kevent.udata  = udata as type_of_udata;
++}
++
++#[test]
++fn test_struct_kevent() {
++    let udata : intptr_t = 12345;
++
++    let expected = libc::kevent{ident: 0xdead_beef,
++                                filter: libc::EVFILT_READ,
++                                flags: libc::EV_ONESHOT | libc::EV_ADD,
++                                fflags: libc::NOTE_CHILD | libc::NOTE_EXIT,
++                                data: 0x1337,
++                                udata: udata as type_of_udata};
++    let actual = KEvent::new(0xdead_beef,
++                             EventFilter::EVFILT_READ,
++                             EventFlag::EV_ONESHOT | EventFlag::EV_ADD,
++                             FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT,
++                             0x1337,
++                             udata);
++    assert!(expected.ident == actual.ident());
++    assert!(expected.filter == actual.filter() as type_of_event_filter);
++    assert!(expected.flags == actual.flags().bits());
++    assert!(expected.fflags == actual.fflags().bits());
++    assert!(expected.data == actual.data() as type_of_data);
++    assert!(expected.udata == actual.udata() as type_of_udata);
++    assert!(mem::size_of::<libc::kevent>() == mem::size_of::<KEvent>());
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/eventfd.rs b/third_party/rust/nix-0.15.0/src/sys/eventfd.rs
+new file mode 100644
+index 0000000000000..c5a54e46a1735
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/eventfd.rs
+@@ -0,0 +1,18 @@
++use libc;
++use std::os::unix::io::RawFd;
++use Result;
++use errno::Errno;
++
++libc_bitflags! {
++    pub struct EfdFlags: libc::c_int {
++        EFD_CLOEXEC; // Since Linux 2.6.27
++        EFD_NONBLOCK; // Since Linux 2.6.27
++        EFD_SEMAPHORE; // Since Linux 2.6.30
++    }
++}
++
++pub fn eventfd(initval: libc::c_uint, flags: EfdFlags) -> Result<RawFd> {
++    let res = unsafe { libc::eventfd(initval, flags.bits()) };
++
++    Errno::result(res).map(|r| r as RawFd)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/inotify.rs b/third_party/rust/nix-0.15.0/src/sys/inotify.rs
+new file mode 100644
+index 0000000000000..e6c2cf64d29dc
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/inotify.rs
+@@ -0,0 +1,230 @@
++//! Monitoring API for filesystem events.
++//!
++//! Inotify is a Linux-only API to monitor filesystems events.
++//!
++//! For more documentation, please read [inotify(7)](http://man7.org/linux/man-pages/man7/inotify.7.html).
++//! 
++//! # Examples
++//!
++//! Monitor all events happening in directory "test":
++//! ```no_run
++//! # use nix::sys::inotify::{AddWatchFlags,InitFlags,Inotify};
++//! #
++//! // We create a new inotify instance.
++//! let instance = Inotify::init(InitFlags::empty()).unwrap();
++//!
++//! // We add a new watch on directory "test" for all events.
++//! let wd = instance.add_watch("test", AddWatchFlags::IN_ALL_EVENTS).unwrap();
++//!
++//! loop {
++//!     // We read from our inotify instance for events.
++//!     let events = instance.read_events().unwrap();
++//!     println!("Events: {:?}", events);
++//! }
++//! ```
++
++use libc;
++use libc::{
++    c_char,
++    c_int,
++};
++use std::ffi::{OsString,OsStr,CStr};
++use std::os::unix::ffi::OsStrExt;
++use std::mem::size_of;
++use std::os::unix::io::{RawFd,AsRawFd,FromRawFd};
++use unistd::read;
++use Result;
++use NixPath;
++use errno::Errno;
++
++libc_bitflags! {
++    /// Configuration options for [`inotify_add_watch`](fn.inotify_add_watch.html).
++    pub struct AddWatchFlags: u32 {
++        IN_ACCESS;
++        IN_MODIFY;
++        IN_ATTRIB;
++        IN_CLOSE_WRITE;
++        IN_CLOSE_NOWRITE;
++        IN_OPEN;
++        IN_MOVED_FROM;
++        IN_MOVED_TO;
++        IN_CREATE;
++        IN_DELETE;
++        IN_DELETE_SELF;
++        IN_MOVE_SELF;
++
++        IN_UNMOUNT;
++        IN_Q_OVERFLOW;
++        IN_IGNORED;
++
++        IN_CLOSE;
++        IN_MOVE;
++
++        IN_ONLYDIR;
++        IN_DONT_FOLLOW;
++
++        IN_ISDIR;
++        IN_ONESHOT;
++        IN_ALL_EVENTS;
++    }
++}
++
++libc_bitflags! {
++    /// Configuration options for [`inotify_init1`](fn.inotify_init1.html).
++    pub struct InitFlags: c_int {
++        IN_CLOEXEC;
++        IN_NONBLOCK;
++    }
++}
++
++/// An inotify instance. This is also a file descriptor, you can feed it to
++/// other interfaces consuming file descriptors, epoll for example.
++#[derive(Debug, Clone, Copy)]
++pub struct Inotify {
++    fd: RawFd
++}
++
++/// This object is returned when you create a new watch on an inotify instance.
++/// It is then returned as part of an event once triggered. It allows you to
++/// know which watch triggered which event. 
++#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd)]
++pub struct WatchDescriptor {
++    wd: i32
++}
++
++/// A single inotify event.
++///
++/// For more documentation see, [inotify(7)](http://man7.org/linux/man-pages/man7/inotify.7.html).
++#[derive(Debug)]
++pub struct InotifyEvent {
++    /// Watch descriptor. This field corresponds to the watch descriptor you
++    /// were issued when calling add_watch. It allows you to know which watch
++    /// this event comes from. 
++    pub wd: WatchDescriptor,
++    /// Event mask. This field is a bitfield describing the exact event that
++    /// occured.
++    pub mask: AddWatchFlags,
++    /// This cookie is a number that allows you to connect related events. For
++    /// now only IN_MOVED_FROM and IN_MOVED_TO can be connected. 
++    pub cookie: u32,
++    /// Filename. This field exists only if the event was triggered for a file
++    /// inside the watched directory.
++    pub name: Option<OsString>
++}
++
++impl Inotify {
++    /// Initialize a new inotify instance.
++    ///
++    /// Returns a Result containing an inotify instance.
++    ///
++    /// For more information see, [inotify_init(2)](http://man7.org/linux/man-pages/man2/inotify_init.2.html).
++    pub fn init(flags: InitFlags) -> Result<Inotify> {
++        let res = Errno::result(unsafe {
++            libc::inotify_init1(flags.bits())
++        });
++
++        res.map(|fd| Inotify { fd })
++    }
++
++    /// Adds a new watch on the target file or directory. 
++    ///
++    /// Returns a watch descriptor. This is not a File Descriptor! 
++    ///
++    /// For more information see, [inotify_add_watch(2)](http://man7.org/linux/man-pages/man2/inotify_add_watch.2.html).
++    pub fn add_watch<P: ?Sized + NixPath>(&self,
++                                          path: &P,
++                                          mask: AddWatchFlags) 
++                                            -> Result<WatchDescriptor>
++    {
++        let res = path.with_nix_path(|cstr| {
++            unsafe {
++                libc::inotify_add_watch(self.fd, cstr.as_ptr(), mask.bits())
++            }
++        })?;
++
++        Errno::result(res).map(|wd| WatchDescriptor { wd })
++    }
++
++    /// Removes an existing watch using the watch descriptor returned by
++    /// inotify_add_watch.
++    ///
++    /// Returns an EINVAL error if the watch descriptor is invalid.
++    ///
++    /// For more information see, [inotify_rm_watch(2)](http://man7.org/linux/man-pages/man2/inotify_rm_watch.2.html).
++    #[cfg(target_os = "linux")]
++    pub fn rm_watch(&self, wd: WatchDescriptor) -> Result<()> {
++        let res = unsafe { libc::inotify_rm_watch(self.fd, wd.wd) };
++
++        Errno::result(res).map(drop)
++    }
++
++    #[cfg(target_os = "android")]
++    pub fn rm_watch(&self, wd: WatchDescriptor) -> Result<()> {
++        let res = unsafe { libc::inotify_rm_watch(self.fd, wd.wd as u32) };
++
++        Errno::result(res).map(drop)
++    }
++
++    /// Reads a collection of events from the inotify file descriptor. This call
++    /// can either be blocking or non blocking depending on whether IN_NONBLOCK
++    /// was set at initialization. 
++    /// 
++    /// Returns as many events as available. If the call was non blocking and no
++    /// events could be read then the EAGAIN error is returned.
++    pub fn read_events(&self) -> Result<Vec<InotifyEvent>> {
++        let header_size = size_of::<libc::inotify_event>();
++        let mut buffer = [0u8; 4096];
++        let mut events = Vec::new();
++        let mut offset = 0;
++
++        let nread = read(self.fd, &mut buffer)?;
++
++        while (nread - offset) >= header_size {
++            let event = unsafe {
++                &*(
++                    buffer
++                        .as_ptr()
++                        .offset(offset as isize) as *const libc::inotify_event
++                )
++            };
++
++            let name = match event.len {
++                0 => None,
++                _ => {
++                    let ptr = unsafe { 
++                        buffer
++                            .as_ptr()
++                            .offset(offset as isize + header_size as isize)
++                            as *const c_char
++                    };
++                    let cstr = unsafe { CStr::from_ptr(ptr) };
++                
++                    Some(OsStr::from_bytes(cstr.to_bytes()).to_owned())
++                }
++            };
++
++            events.push(InotifyEvent {
++                wd: WatchDescriptor { wd: event.wd },
++                mask: AddWatchFlags::from_bits_truncate(event.mask),
++                cookie: event.cookie,
++                name
++            });
++
++            offset += header_size + event.len as usize;
++        }
++
++        Ok(events)
++    }
++}
++
++impl AsRawFd for Inotify {
++    fn as_raw_fd(&self) -> RawFd {
++        self.fd
++    }
++}
++
++impl FromRawFd for Inotify {
++    unsafe fn from_raw_fd(fd: RawFd) -> Self {
++        Inotify { fd }
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/ioctl/bsd.rs b/third_party/rust/nix-0.15.0/src/sys/ioctl/bsd.rs
+new file mode 100644
+index 0000000000000..9b8b0ff1a155f
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/ioctl/bsd.rs
+@@ -0,0 +1,102 @@
++/// The datatype used for the ioctl number
++#[doc(hidden)]
++pub type ioctl_num_type = ::libc::c_ulong;
++/// The datatype used for the 3rd argument
++#[doc(hidden)]
++pub type ioctl_param_type = ::libc::c_int;
++
++mod consts {
++    use ::sys::ioctl::ioctl_num_type;
++    #[doc(hidden)]
++    pub const VOID: ioctl_num_type = 0x2000_0000;
++    #[doc(hidden)]
++    pub const OUT: ioctl_num_type = 0x4000_0000;
++    #[doc(hidden)]
++    pub const IN: ioctl_num_type = 0x8000_0000;
++    #[doc(hidden)]
++    pub const INOUT: ioctl_num_type = (IN|OUT);
++    #[doc(hidden)]
++    pub const IOCPARM_MASK: ioctl_num_type = 0x1fff;
++}
++
++pub use self::consts::*;
++
++#[macro_export]
++#[doc(hidden)]
++macro_rules! ioc {
++    ($inout:expr, $group:expr, $num:expr, $len:expr) => (
++        $inout | (($len as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::IOCPARM_MASK) << 16) | (($group as $crate::sys::ioctl::ioctl_num_type) << 8) | ($num as $crate::sys::ioctl::ioctl_num_type)
++    )
++}
++
++/// Generate an ioctl request code for a command that passes no data.
++///
++/// This is equivalent to the `_IO()` macro exposed by the C ioctl API.
++///
++/// You should only use this macro directly if the `ioctl` you're working
++/// with is "bad" and you cannot use `ioctl_none!()` directly.
++///
++/// # Example
++///
++/// ```
++/// # #[macro_use] extern crate nix;
++/// const KVMIO: u8 = 0xAE;
++/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03));
++/// # fn main() {}
++/// ```
++#[macro_export(local_inner_macros)]
++macro_rules! request_code_none {
++    ($g:expr, $n:expr) => (ioc!($crate::sys::ioctl::VOID, $g, $n, 0))
++}
++
++/// Generate an ioctl request code for a command that passes an integer
++///
++/// This is equivalent to the `_IOWINT()` macro exposed by the C ioctl API.
++///
++/// You should only use this macro directly if the `ioctl` you're working
++/// with is "bad" and you cannot use `ioctl_write_int!()` directly.
++#[macro_export(local_inner_macros)]
++macro_rules! request_code_write_int {
++    ($g:expr, $n:expr) => (ioc!($crate::sys::ioctl::VOID, $g, $n, ::std::mem::size_of::<$crate::libc::c_int>()))
++}
++
++/// Generate an ioctl request code for a command that reads.
++///
++/// This is equivalent to the `_IOR()` macro exposed by the C ioctl API.
++///
++/// You should only use this macro directly if the `ioctl` you're working
++/// with is "bad" and you cannot use `ioctl_read!()` directly.
++///
++/// The read/write direction is relative to userland, so this
++/// command would be userland is reading and the kernel is
++/// writing.
++#[macro_export(local_inner_macros)]
++macro_rules! request_code_read {
++    ($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::OUT, $g, $n, $len))
++}
++
++/// Generate an ioctl request code for a command that writes.
++///
++/// This is equivalent to the `_IOW()` macro exposed by the C ioctl API.
++///
++/// You should only use this macro directly if the `ioctl` you're working
++/// with is "bad" and you cannot use `ioctl_write!()` directly.
++///
++/// The read/write direction is relative to userland, so this
++/// command would be userland is writing and the kernel is
++/// reading.
++#[macro_export(local_inner_macros)]
++macro_rules! request_code_write {
++    ($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::IN, $g, $n, $len))
++}
++
++/// Generate an ioctl request code for a command that reads and writes.
++///
++/// This is equivalent to the `_IOWR()` macro exposed by the C ioctl API.
++///
++/// You should only use this macro directly if the `ioctl` you're working
++/// with is "bad" and you cannot use `ioctl_readwrite!()` directly.
++#[macro_export(local_inner_macros)]
++macro_rules! request_code_readwrite {
++    ($g:expr, $n:expr, $len:expr) => (ioc!($crate::sys::ioctl::INOUT, $g, $n, $len))
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/ioctl/linux.rs b/third_party/rust/nix-0.15.0/src/sys/ioctl/linux.rs
+new file mode 100644
+index 0000000000000..9cdac72a4b80b
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/ioctl/linux.rs
+@@ -0,0 +1,140 @@
++/// The datatype used for the ioctl number
++#[cfg(any(target_os = "android", target_env = "musl"))]
++#[doc(hidden)]
++pub type ioctl_num_type = ::libc::c_int;
++#[cfg(not(any(target_os = "android", target_env = "musl")))]
++#[doc(hidden)]
++pub type ioctl_num_type = ::libc::c_ulong;
++/// The datatype used for the 3rd argument
++#[doc(hidden)]
++pub type ioctl_param_type = ::libc::c_ulong;
++
++#[doc(hidden)]
++pub const NRBITS: ioctl_num_type = 8;
++#[doc(hidden)]
++pub const TYPEBITS: ioctl_num_type = 8;
++
++#[cfg(any(target_arch = "mips", target_arch = "mips64", target_arch = "powerpc", target_arch = "powerpc64", target_arch = "sparc64"))]
++mod consts {
++    #[doc(hidden)]
++    pub const NONE: u8 = 1;
++    #[doc(hidden)]
++    pub const READ: u8 = 2;
++    #[doc(hidden)]
++    pub const WRITE: u8 = 4;
++    #[doc(hidden)]
++    pub const SIZEBITS: u8 = 13;
++    #[doc(hidden)]
++    pub const DIRBITS: u8 = 3;
++}
++
++// "Generic" ioctl protocol
++#[cfg(any(target_arch = "x86",
++          target_arch = "arm",
++          target_arch = "s390x",
++          target_arch = "x86_64",
++          target_arch = "aarch64"))]
++mod consts {
++    #[doc(hidden)]
++    pub const NONE: u8 = 0;
++    #[doc(hidden)]
++    pub const READ: u8 = 2;
++    #[doc(hidden)]
++    pub const WRITE: u8 = 1;
++    #[doc(hidden)]
++    pub const SIZEBITS: u8 = 14;
++    #[doc(hidden)]
++    pub const DIRBITS: u8 = 2;
++}
++
++pub use self::consts::*;
++
++#[doc(hidden)]
++pub const NRSHIFT: ioctl_num_type = 0;
++#[doc(hidden)]
++pub const TYPESHIFT: ioctl_num_type = NRSHIFT + NRBITS as ioctl_num_type;
++#[doc(hidden)]
++pub const SIZESHIFT: ioctl_num_type = TYPESHIFT + TYPEBITS as ioctl_num_type;
++#[doc(hidden)]
++pub const DIRSHIFT: ioctl_num_type = SIZESHIFT + SIZEBITS as ioctl_num_type;
++
++#[doc(hidden)]
++pub const NRMASK: ioctl_num_type = (1 << NRBITS) - 1;
++#[doc(hidden)]
++pub const TYPEMASK: ioctl_num_type = (1 << TYPEBITS) - 1;
++#[doc(hidden)]
++pub const SIZEMASK: ioctl_num_type = (1 << SIZEBITS) - 1;
++#[doc(hidden)]
++pub const DIRMASK: ioctl_num_type = (1 << DIRBITS) - 1;
++
++/// Encode an ioctl command.
++#[macro_export]
++#[doc(hidden)]
++macro_rules! ioc {
++    ($dir:expr, $ty:expr, $nr:expr, $sz:expr) => (
++        (($dir as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::DIRMASK) << $crate::sys::ioctl::DIRSHIFT) |
++        (($ty as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::TYPEMASK) << $crate::sys::ioctl::TYPESHIFT) |
++        (($nr as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::NRMASK) << $crate::sys::ioctl::NRSHIFT) |
++        (($sz as $crate::sys::ioctl::ioctl_num_type & $crate::sys::ioctl::SIZEMASK) << $crate::sys::ioctl::SIZESHIFT))
++}
++
++/// Generate an ioctl request code for a command that passes no data.
++///
++/// This is equivalent to the `_IO()` macro exposed by the C ioctl API.
++///
++/// You should only use this macro directly if the `ioctl` you're working
++/// with is "bad" and you cannot use `ioctl_none!()` directly.
++///
++/// # Example
++///
++/// ```
++/// # #[macro_use] extern crate nix;
++/// const KVMIO: u8 = 0xAE;
++/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03));
++/// # fn main() {}
++/// ```
++#[macro_export(local_inner_macros)]
++macro_rules! request_code_none {
++    ($ty:expr, $nr:expr) => (ioc!($crate::sys::ioctl::NONE, $ty, $nr, 0))
++}
++
++/// Generate an ioctl request code for a command that reads.
++///
++/// This is equivalent to the `_IOR()` macro exposed by the C ioctl API.
++///
++/// You should only use this macro directly if the `ioctl` you're working
++/// with is "bad" and you cannot use `ioctl_read!()` directly.
++///
++/// The read/write direction is relative to userland, so this
++/// command would be userland is reading and the kernel is
++/// writing.
++#[macro_export(local_inner_macros)]
++macro_rules! request_code_read {
++    ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::READ, $ty, $nr, $sz))
++}
++
++/// Generate an ioctl request code for a command that writes.
++///
++/// This is equivalent to the `_IOW()` macro exposed by the C ioctl API.
++///
++/// You should only use this macro directly if the `ioctl` you're working
++/// with is "bad" and you cannot use `ioctl_write!()` directly.
++///
++/// The read/write direction is relative to userland, so this
++/// command would be userland is writing and the kernel is
++/// reading.
++#[macro_export(local_inner_macros)]
++macro_rules! request_code_write {
++    ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::WRITE, $ty, $nr, $sz))
++}
++
++/// Generate an ioctl request code for a command that reads and writes.
++///
++/// This is equivalent to the `_IOWR()` macro exposed by the C ioctl API.
++///
++/// You should only use this macro directly if the `ioctl` you're working
++/// with is "bad" and you cannot use `ioctl_readwrite!()` directly.
++#[macro_export(local_inner_macros)]
++macro_rules! request_code_readwrite {
++    ($ty:expr, $nr:expr, $sz:expr) => (ioc!($crate::sys::ioctl::READ | $crate::sys::ioctl::WRITE, $ty, $nr, $sz))
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/ioctl/mod.rs b/third_party/rust/nix-0.15.0/src/sys/ioctl/mod.rs
+new file mode 100644
+index 0000000000000..4513bf877434a
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/ioctl/mod.rs
+@@ -0,0 +1,778 @@
++//! Provide helpers for making ioctl system calls.
++//!
++//! This library is pretty low-level and messy. `ioctl` is not fun.
++//!
++//! What is an `ioctl`?
++//! ===================
++//!
++//! The `ioctl` syscall is the grab-bag syscall on POSIX systems. Don't want to add a new
++//! syscall? Make it an `ioctl`! `ioctl` refers to both the syscall, and the commands that can be
++//! sent with it. `ioctl` stands for "IO control", and the commands are always sent to a file
++//! descriptor.
++//!
++//! It is common to see `ioctl`s used for the following purposes:
++//!
++//!   * Provide read/write access to out-of-band data related to a device such as configuration
++//!     (for instance, setting serial port options)
++//!   * Provide a mechanism for performing full-duplex data transfers (for instance, xfer on SPI
++//!     devices).
++//!   * Provide access to control functions on a device (for example, on Linux you can send
++//!     commands like pause, resume, and eject to the CDROM device.
++//!   * Do whatever else the device driver creator thought made most sense.
++//!
++//! `ioctl`s are synchronous system calls and are similar to read and write calls in that regard.
++//! They operate on file descriptors and have an identifier that specifies what the ioctl is.
++//! Additionally they may read or write data and therefore need to pass along a data pointer.
++//! Besides the semantics of the ioctls being confusing, the generation of this identifer can also
++//! be difficult.
++//!
++//! Historically `ioctl` numbers were arbitrary hard-coded values. In Linux (before 2.6) and some
++//! unices this has changed to a more-ordered system where the ioctl numbers are partitioned into
++//! subcomponents (For linux this is documented in
++//! [`Documentation/ioctl/ioctl-number.txt`](http://elixir.free-electrons.com/linux/latest/source/Documentation/ioctl/ioctl-number.txt)):
++//!
++//!   * Number: The actual ioctl ID
++//!   * Type: A grouping of ioctls for a common purpose or driver
++//!   * Size: The size in bytes of the data that will be transferred
++//!   * Direction: Whether there is any data and if it's read, write, or both
++//!
++//! Newer drivers should not generate complete integer identifiers for their `ioctl`s instead
++//! preferring to use the 4 components above to generate the final ioctl identifier. Because of
++//! how old `ioctl`s are, however, there are many hard-coded `ioctl` identifiers. These are
++//! commonly referred to as "bad" in `ioctl` documentation.
++//!
++//! Defining `ioctl`s
++//! =================
++//!
++//! This library provides several `ioctl_*!` macros for binding `ioctl`s. These generate public
++//! unsafe functions that can then be used for calling the ioctl. This macro has a few different
++//! ways it can be used depending on the specific ioctl you're working with.
++//!
++//! A simple `ioctl` is `SPI_IOC_RD_MODE`. This ioctl works with the SPI interface on Linux. This
++//! specific `ioctl` reads the mode of the SPI device as a `u8`. It's declared in
++//! `/include/uapi/linux/spi/spidev.h` as `_IOR(SPI_IOC_MAGIC, 1, __u8)`. Since it uses the `_IOR`
++//! macro, we know it's a `read` ioctl and can use the `ioctl_read!` macro as follows:
++//!
++//! ```
++//! # #[macro_use] extern crate nix;
++//! const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
++//! const SPI_IOC_TYPE_MODE: u8 = 1;
++//! ioctl_read!(spi_read_mode, SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, u8);
++//! # fn main() {}
++//! ```
++//!
++//! This generates the function:
++//!
++//! ```
++//! # #[macro_use] extern crate nix;
++//! # use std::mem;
++//! # use nix::{libc, Result};
++//! # use nix::errno::Errno;
++//! # use nix::libc::c_int as c_int;
++//! # const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
++//! # const SPI_IOC_TYPE_MODE: u8 = 1;
++//! pub unsafe fn spi_read_mode(fd: c_int, data: *mut u8) -> Result<c_int> {
++//!     let res = libc::ioctl(fd, request_code_read!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, mem::size_of::<u8>()), data);
++//!     Errno::result(res)
++//! }
++//! # fn main() {}
++//! ```
++//!
++//! The return value for the wrapper functions generated by the `ioctl_*!` macros are `nix::Error`s.
++//! These are generated by assuming the return value of the ioctl is `-1` on error and everything
++//! else is a valid return value. If this is not the case, `Result::map` can be used to map some
++//! of the range of "good" values (-Inf..-2, 0..Inf) into a smaller range in a helper function.
++//!
++//! Writing `ioctl`s generally use pointers as their data source and these should use the
++//! `ioctl_write_ptr!`. But in some cases an `int` is passed directly. For these `ioctl`s use the
++//! `ioctl_write_int!` macro. This variant does not take a type as the last argument:
++//!
++//! ```
++//! # #[macro_use] extern crate nix;
++//! const HCI_IOC_MAGIC: u8 = b'k';
++//! const HCI_IOC_HCIDEVUP: u8 = 1;
++//! ioctl_write_int!(hci_dev_up, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP);
++//! # fn main() {}
++//! ```
++//!
++//! Some `ioctl`s don't transfer any data, and those should use `ioctl_none!`. This macro
++//! doesn't take a type and so it is declared similar to the `write_int` variant shown above.
++//!
++//! The mode for a given `ioctl` should be clear from the documentation if it has good
++//! documentation. Otherwise it will be clear based on the macro used to generate the `ioctl`
++//! number where `_IO`, `_IOR`, `_IOW`, and `_IOWR` map to "none", "read", "write_*", and "readwrite"
++//! respectively. To determine the specific `write_` variant to use you'll need to find
++//! what the argument type is supposed to be. If it's an `int`, then `write_int` should be used,
++//! otherwise it should be a pointer and `write_ptr` should be used. On Linux the
++//! [`ioctl_list` man page](http://man7.org/linux/man-pages/man2/ioctl_list.2.html) describes a
++//! large number of `ioctl`s and describes their argument data type.
++//!
++//! Using "bad" `ioctl`s
++//! --------------------
++//!
++//! As mentioned earlier, there are many old `ioctl`s that do not use the newer method of
++//! generating `ioctl` numbers and instead use hardcoded values. These can be used with the
++//! `ioctl_*_bad!` macros. This naming comes from the Linux kernel which refers to these
++//! `ioctl`s as "bad". These are a different variant as they bypass calling the macro that generates
++//! the ioctl number and instead use the defined value directly.
++//!
++//! For example the `TCGETS` `ioctl` reads a `termios` data structure for a given file descriptor.
++//! It's defined as `0x5401` in `ioctls.h` on Linux and can be implemented as:
++//!
++//! ```
++//! # #[macro_use] extern crate nix;
++//! # #[cfg(any(target_os = "android", target_os = "linux"))]
++//! # use nix::libc::TCGETS as TCGETS;
++//! # #[cfg(any(target_os = "android", target_os = "linux"))]
++//! # use nix::libc::termios as termios;
++//! # #[cfg(any(target_os = "android", target_os = "linux"))]
++//! ioctl_read_bad!(tcgets, TCGETS, termios);
++//! # fn main() {}
++//! ```
++//!
++//! The generated function has the same form as that generated by `ioctl_read!`:
++//!
++//! ```text
++//! pub unsafe fn tcgets(fd: c_int, data: *mut termios) -> Result<c_int>;
++//! ```
++//!
++//! Working with Arrays
++//! -------------------
++//!
++//! Some `ioctl`s work with entire arrays of elements. These are supported by the `ioctl_*_buf`
++//! family of macros: `ioctl_read_buf`, `ioctl_write_buf`, and `ioctl_readwrite_buf`. Note that
++//! there are no "bad" versions for working with buffers. The generated functions include a `len`
++//! argument to specify the number of elements (where the type of each element is specified in the
++//! macro).
++//!
++//! Again looking to the SPI `ioctl`s on Linux for an example, there is a `SPI_IOC_MESSAGE` `ioctl`
++//! that queues up multiple SPI messages by writing an entire array of `spi_ioc_transfer` structs.
++//! `linux/spi/spidev.h` defines a macro to calculate the `ioctl` number like:
++//!
++//! ```C
++//! #define SPI_IOC_MAGIC 'k'
++//! #define SPI_MSGSIZE(N) ...
++//! #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
++//! ```
++//!
++//! The `SPI_MSGSIZE(N)` calculation is already handled by the `ioctl_*!` macros, so all that's
++//! needed to define this `ioctl` is:
++//!
++//! ```
++//! # #[macro_use] extern crate nix;
++//! const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
++//! const SPI_IOC_TYPE_MESSAGE: u8 = 0;
++//! # pub struct spi_ioc_transfer(u64);
++//! ioctl_write_buf!(spi_transfer, SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, spi_ioc_transfer);
++//! # fn main() {}
++//! ```
++//!
++//! This generates a function like:
++//!
++//! ```
++//! # #[macro_use] extern crate nix;
++//! # use std::mem;
++//! # use nix::{libc, Result};
++//! # use nix::errno::Errno;
++//! # use nix::libc::c_int as c_int;
++//! # const SPI_IOC_MAGIC: u8 = b'k';
++//! # const SPI_IOC_TYPE_MESSAGE: u8 = 0;
++//! # pub struct spi_ioc_transfer(u64);
++//! pub unsafe fn spi_message(fd: c_int, data: &mut [spi_ioc_transfer]) -> Result<c_int> {
++//!     let res = libc::ioctl(fd,
++//!                           request_code_write!(SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, data.len() * mem::size_of::<spi_ioc_transfer>()),
++//!                           data);
++//!     Errno::result(res)
++//! }
++//! # fn main() {}
++//! ```
++//!
++//! Finding `ioctl` Documentation
++//! -----------------------------
++//!
++//! For Linux, look at your system's headers. For example, `/usr/include/linux/input.h` has a lot
++//! of lines defining macros which use `_IO`, `_IOR`, `_IOW`, `_IOC`, and `_IOWR`. Some `ioctl`s are
++//! documented directly in the headers defining their constants, but others have more extensive
++//! documentation in man pages (like termios' `ioctl`s which are in `tty_ioctl(4)`).
++//!
++//! Documenting the Generated Functions
++//! ===================================
++//!
++//! In many cases, users will wish for the functions generated by the `ioctl`
++//! macro to be public and documented. For this reason, the generated functions
++//! are public by default. If you wish to hide the ioctl, you will need to put
++//! them in a private module.
++//!
++//! For documentation, it is possible to use doc comments inside the `ioctl_*!` macros. Here is an
++//! example :
++//!
++//! ```
++//! # #[macro_use] extern crate nix;
++//! # use nix::libc::c_int;
++//! ioctl_read! {
++//!     /// Make the given terminal the controlling terminal of the calling process. The calling
++//!     /// process must be a session leader and not have a controlling terminal already. If the
++//!     /// terminal is already the controlling terminal of a different session group then the
++//!     /// ioctl will fail with **EPERM**, unless the caller is root (more precisely: has the
++//!     /// **CAP_SYS_ADMIN** capability) and arg equals 1, in which case the terminal is stolen
++//!     /// and all processes that had it as controlling terminal lose it.
++//!     tiocsctty, b't', 19, c_int
++//! }
++//!
++//! # fn main() {}
++//! ```
++#[cfg(any(target_os = "android", target_os = "linux"))]
++#[macro_use]
++mod linux;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub use self::linux::*;
++
++#[cfg(any(target_os = "dragonfly",
++          target_os = "freebsd",
++          target_os = "ios",
++          target_os = "macos",
++          target_os = "netbsd",
++          target_os = "openbsd"))]
++#[macro_use]
++mod bsd;
++
++#[cfg(any(target_os = "dragonfly",
++          target_os = "freebsd",
++          target_os = "ios",
++          target_os = "macos",
++          target_os = "netbsd",
++          target_os = "openbsd"))]
++pub use self::bsd::*;
++
++/// Convert raw ioctl return value to a Nix result
++#[macro_export]
++#[doc(hidden)]
++macro_rules! convert_ioctl_res {
++    ($w:expr) => (
++        {
++            $crate::errno::Errno::result($w)
++        }
++    );
++}
++
++/// Generates a wrapper function for an ioctl that passes no data to the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl identifier
++/// * The ioctl sequence number
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++///
++/// # Example
++///
++/// The `videodev2` driver on Linux defines the `log_status` `ioctl` as:
++///
++/// ```C
++/// #define VIDIOC_LOG_STATUS         _IO('V', 70)
++/// ```
++///
++/// This can be implemented in Rust like:
++///
++/// ```no_run
++/// # #[macro_use] extern crate nix;
++/// ioctl_none!(log_status, b'V', 70);
++/// fn main() {}
++/// ```
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_none {
++    ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => (
++        $(#[$attr])*
++        pub unsafe fn $name(fd: $crate::libc::c_int)
++                            -> $crate::Result<$crate::libc::c_int> {
++            convert_ioctl_res!($crate::libc::ioctl(fd, request_code_none!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type))
++        }
++    )
++}
++
++/// Generates a wrapper function for a "bad" ioctl that passes no data to the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl request code
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++///
++/// # Example
++///
++/// ```no_run
++/// # #[macro_use] extern crate nix;
++/// # extern crate libc;
++/// # use libc::TIOCNXCL;
++/// # use std::fs::File;
++/// # use std::os::unix::io::AsRawFd;
++/// ioctl_none_bad!(tiocnxcl, TIOCNXCL);
++/// fn main() {
++///     let file = File::open("/dev/ttyUSB0").unwrap();
++///     unsafe { tiocnxcl(file.as_raw_fd()) }.unwrap();
++/// }
++/// ```
++// TODO: add an example using request_code_*!()
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_none_bad {
++    ($(#[$attr:meta])* $name:ident, $nr:expr) => (
++        $(#[$attr])*
++        pub unsafe fn $name(fd: $crate::libc::c_int)
++                            -> $crate::Result<$crate::libc::c_int> {
++            convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type))
++        }
++    )
++}
++
++/// Generates a wrapper function for an ioctl that reads data from the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl identifier
++/// * The ioctl sequence number
++/// * The data type passed by this ioctl
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++///
++/// # Example
++///
++/// ```
++/// # #[macro_use] extern crate nix;
++/// const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
++/// const SPI_IOC_TYPE_MODE: u8 = 1;
++/// ioctl_read!(spi_read_mode, SPI_IOC_MAGIC, SPI_IOC_TYPE_MODE, u8);
++/// # fn main() {}
++/// ```
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_read {
++    ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
++        $(#[$attr])*
++        pub unsafe fn $name(fd: $crate::libc::c_int,
++                            data: *mut $ty)
++                            -> $crate::Result<$crate::libc::c_int> {
++            convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
++        }
++    )
++}
++
++/// Generates a wrapper function for a "bad" ioctl that reads data from the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl request code
++/// * The data type passed by this ioctl
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++///
++/// # Example
++///
++/// ```
++/// # extern crate libc;
++/// # #[macro_use] extern crate nix;
++/// # #[cfg(any(target_os = "android", target_os = "linux"))]
++/// ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios);
++/// # fn main() {}
++/// ```
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_read_bad {
++    ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => (
++        $(#[$attr])*
++        pub unsafe fn $name(fd: $crate::libc::c_int,
++                            data: *mut $ty)
++                            -> $crate::Result<$crate::libc::c_int> {
++            convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
++        }
++    )
++}
++
++/// Generates a wrapper function for an ioctl that writes data through a pointer to the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl identifier
++/// * The ioctl sequence number
++/// * The data type passed by this ioctl
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *const DATA_TYPE) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++///
++/// # Example
++///
++/// ```
++/// # #[macro_use] extern crate nix;
++/// # pub struct v4l2_audio {}
++/// ioctl_write_ptr!(s_audio, b'V', 34, v4l2_audio);
++/// # fn main() {}
++/// ```
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_write_ptr {
++    ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
++        $(#[$attr])*
++        pub unsafe fn $name(fd: $crate::libc::c_int,
++                            data: *const $ty)
++                            -> $crate::Result<$crate::libc::c_int> {
++            convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
++        }
++    )
++}
++
++/// Generates a wrapper function for a "bad" ioctl that writes data through a pointer to the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl request code
++/// * The data type passed by this ioctl
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *const DATA_TYPE) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++///
++/// # Example
++///
++/// ```
++/// # extern crate libc;
++/// # #[macro_use] extern crate nix;
++/// # #[cfg(any(target_os = "android", target_os = "linux"))]
++/// ioctl_write_ptr_bad!(tcsets, libc::TCSETS, libc::termios);
++/// # fn main() {}
++/// ```
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_write_ptr_bad {
++    ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => (
++        $(#[$attr])*
++        pub unsafe fn $name(fd: $crate::libc::c_int,
++                            data: *const $ty)
++                            -> $crate::Result<$crate::libc::c_int> {
++            convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
++        }
++    )
++}
++
++cfg_if!{
++    if #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] {
++        /// Generates a wrapper function for a ioctl that writes an integer to the kernel.
++        ///
++        /// The arguments to this macro are:
++        ///
++        /// * The function name
++        /// * The ioctl identifier
++        /// * The ioctl sequence number
++        ///
++        /// The generated function has the following signature:
++        ///
++        /// ```rust,ignore
++        /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: nix::sys::ioctl::ioctl_param_type) -> Result<libc::c_int>
++        /// ```
++        ///
++        /// `nix::sys::ioctl::ioctl_param_type` depends on the OS:
++        /// *   BSD - `libc::c_int`
++        /// *   Linux - `libc::c_ulong`
++        ///
++        /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++        ///
++        /// # Example
++        ///
++        /// ```
++        /// # #[macro_use] extern crate nix;
++        /// ioctl_write_int!(vt_activate, b'v', 4);
++        /// # fn main() {}
++        /// ```
++        #[macro_export(local_inner_macros)]
++        macro_rules! ioctl_write_int {
++            ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => (
++                $(#[$attr])*
++                pub unsafe fn $name(fd: $crate::libc::c_int,
++                                    data: $crate::sys::ioctl::ioctl_param_type)
++                                    -> $crate::Result<$crate::libc::c_int> {
++                    convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write_int!($ioty, $nr) as $crate::sys::ioctl::ioctl_num_type, data))
++                }
++            )
++        }
++    } else {
++        /// Generates a wrapper function for a ioctl that writes an integer to the kernel.
++        ///
++        /// The arguments to this macro are:
++        ///
++        /// * The function name
++        /// * The ioctl identifier
++        /// * The ioctl sequence number
++        ///
++        /// The generated function has the following signature:
++        ///
++        /// ```rust,ignore
++        /// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: nix::sys::ioctl::ioctl_param_type) -> Result<libc::c_int>
++        /// ```
++        ///
++        /// `nix::sys::ioctl::ioctl_param_type` depends on the OS:
++        /// *   BSD - `libc::c_int`
++        /// *   Linux - `libc::c_ulong`
++        ///
++        /// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++        ///
++        /// # Example
++        ///
++        /// ```
++        /// # #[macro_use] extern crate nix;
++        /// const HCI_IOC_MAGIC: u8 = b'k';
++        /// const HCI_IOC_HCIDEVUP: u8 = 1;
++        /// ioctl_write_int!(hci_dev_up, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP);
++        /// # fn main() {}
++        /// ```
++        #[macro_export(local_inner_macros)]
++        macro_rules! ioctl_write_int {
++            ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr) => (
++                $(#[$attr])*
++                pub unsafe fn $name(fd: $crate::libc::c_int,
++                                    data: $crate::sys::ioctl::ioctl_param_type)
++                                    -> $crate::Result<$crate::libc::c_int> {
++                    convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, ::std::mem::size_of::<$crate::libc::c_int>()) as $crate::sys::ioctl::ioctl_num_type, data))
++                }
++            )
++        }
++    }
++}
++
++/// Generates a wrapper function for a "bad" ioctl that writes an integer to the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl request code
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: libc::c_int) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++///
++/// # Examples
++///
++/// ```
++/// # extern crate libc;
++/// # #[macro_use] extern crate nix;
++/// # #[cfg(any(target_os = "android", target_os = "linux"))]
++/// ioctl_write_int_bad!(tcsbrk, libc::TCSBRK);
++/// # fn main() {}
++/// ```
++///
++/// ```rust
++/// # #[macro_use] extern crate nix;
++/// const KVMIO: u8 = 0xAE;
++/// ioctl_write_int_bad!(kvm_create_vm, request_code_none!(KVMIO, 0x03));
++/// # fn main() {}
++/// ```
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_write_int_bad {
++    ($(#[$attr:meta])* $name:ident, $nr:expr) => (
++        $(#[$attr])*
++        pub unsafe fn $name(fd: $crate::libc::c_int,
++                            data: $crate::libc::c_int)
++                            -> $crate::Result<$crate::libc::c_int> {
++            convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
++        }
++    )
++}
++
++/// Generates a wrapper function for an ioctl that reads and writes data to the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl identifier
++/// * The ioctl sequence number
++/// * The data type passed by this ioctl
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++///
++/// # Example
++///
++/// ```
++/// # #[macro_use] extern crate nix;
++/// # pub struct v4l2_audio {}
++/// ioctl_readwrite!(enum_audio, b'V', 65, v4l2_audio);
++/// # fn main() {}
++/// ```
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_readwrite {
++    ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
++        $(#[$attr])*
++        pub unsafe fn $name(fd: $crate::libc::c_int,
++                            data: *mut $ty)
++                            -> $crate::Result<$crate::libc::c_int> {
++            convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
++        }
++    )
++}
++
++/// Generates a wrapper function for a "bad" ioctl that reads and writes data to the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl request code
++/// * The data type passed by this ioctl
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: *mut DATA_TYPE) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++// TODO: Find an example for ioctl_readwrite_bad
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_readwrite_bad {
++    ($(#[$attr:meta])* $name:ident, $nr:expr, $ty:ty) => (
++        $(#[$attr])*
++        pub unsafe fn $name(fd: $crate::libc::c_int,
++                            data: *mut $ty)
++                            -> $crate::Result<$crate::libc::c_int> {
++            convert_ioctl_res!($crate::libc::ioctl(fd, $nr as $crate::sys::ioctl::ioctl_num_type, data))
++        }
++    )
++}
++
++/// Generates a wrapper function for an ioctl that reads an array of elements from the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl identifier
++/// * The ioctl sequence number
++/// * The data type passed by this ioctl
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &mut [DATA_TYPE]) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++// TODO: Find an example for ioctl_read_buf
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_read_buf {
++    ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
++        $(#[$attr])*
++        pub unsafe fn $name(fd: $crate::libc::c_int,
++                            data: &mut [$ty])
++                            -> $crate::Result<$crate::libc::c_int> {
++            convert_ioctl_res!($crate::libc::ioctl(fd, request_code_read!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
++        }
++    )
++}
++
++/// Generates a wrapper function for an ioctl that writes an array of elements to the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl identifier
++/// * The ioctl sequence number
++/// * The data type passed by this ioctl
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &[DATA_TYPE]) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++///
++/// # Examples
++///
++/// ```
++/// # #[macro_use] extern crate nix;
++/// const SPI_IOC_MAGIC: u8 = b'k'; // Defined in linux/spi/spidev.h
++/// const SPI_IOC_TYPE_MESSAGE: u8 = 0;
++/// # pub struct spi_ioc_transfer(u64);
++/// ioctl_write_buf!(spi_transfer, SPI_IOC_MAGIC, SPI_IOC_TYPE_MESSAGE, spi_ioc_transfer);
++/// # fn main() {}
++/// ```
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_write_buf {
++    ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
++        $(#[$attr])*
++        pub unsafe fn $name(fd: $crate::libc::c_int,
++                            data: &[$ty])
++                            -> $crate::Result<$crate::libc::c_int> {
++            convert_ioctl_res!($crate::libc::ioctl(fd, request_code_write!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
++        }
++    )
++}
++
++/// Generates a wrapper function for an ioctl that reads and writes an array of elements to the kernel.
++///
++/// The arguments to this macro are:
++///
++/// * The function name
++/// * The ioctl identifier
++/// * The ioctl sequence number
++/// * The data type passed by this ioctl
++///
++/// The generated function has the following signature:
++///
++/// ```rust,ignore
++/// pub unsafe fn FUNCTION_NAME(fd: libc::c_int, data: &mut [DATA_TYPE]) -> Result<libc::c_int>
++/// ```
++///
++/// For a more in-depth explanation of ioctls, see [`::sys::ioctl`](sys/ioctl/index.html).
++// TODO: Find an example for readwrite_buf
++#[macro_export(local_inner_macros)]
++macro_rules! ioctl_readwrite_buf {
++    ($(#[$attr:meta])* $name:ident, $ioty:expr, $nr:expr, $ty:ty) => (
++        $(#[$attr])*
++        pub unsafe fn $name(fd: $crate::libc::c_int,
++                            data: &mut [$ty])
++                            -> $crate::Result<$crate::libc::c_int> {
++            convert_ioctl_res!($crate::libc::ioctl(fd, request_code_readwrite!($ioty, $nr, data.len() * ::std::mem::size_of::<$ty>()) as $crate::sys::ioctl::ioctl_num_type, data))
++        }
++    )
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/memfd.rs b/third_party/rust/nix-0.15.0/src/sys/memfd.rs
+new file mode 100644
+index 0000000000000..9672429b31e7f
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/memfd.rs
+@@ -0,0 +1,20 @@
++use libc;
++use std::os::unix::io::RawFd;
++use Result;
++use errno::Errno;
++use std::ffi::CStr;
++
++libc_bitflags!(
++    pub struct MemFdCreateFlag: libc::c_uint {
++        MFD_CLOEXEC;
++        MFD_ALLOW_SEALING;
++    }
++);
++
++pub fn memfd_create(name: &CStr, flags: MemFdCreateFlag) -> Result<RawFd> {
++    let res = unsafe {
++        libc::syscall(libc::SYS_memfd_create, name.as_ptr(), flags.bits())
++    };
++
++    Errno::result(res).map(|r| r as RawFd)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/mman.rs b/third_party/rust/nix-0.15.0/src/sys/mman.rs
+new file mode 100644
+index 0000000000000..4e250501dd0f0
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/mman.rs
+@@ -0,0 +1,325 @@
++use {Error, Result};
++#[cfg(not(target_os = "android"))]
++use NixPath;
++use errno::Errno;
++#[cfg(not(target_os = "android"))]
++use fcntl::OFlag;
++use libc::{self, c_int, c_void, size_t, off_t};
++#[cfg(not(target_os = "android"))]
++use sys::stat::Mode;
++use std::os::unix::io::RawFd;
++
++libc_bitflags!{
++    /// Desired memory protection of a memory mapping.
++    pub struct ProtFlags: c_int {
++        /// Pages cannot be accessed.
++        PROT_NONE;
++        /// Pages can be read.
++        PROT_READ;
++        /// Pages can be written.
++        PROT_WRITE;
++        /// Pages can be executed
++        PROT_EXEC;
++        /// Apply protection up to the end of a mapping that grows upwards.
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        PROT_GROWSDOWN;
++        /// Apply protection down to the beginning of a mapping that grows downwards.
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        PROT_GROWSUP;
++    }
++}
++
++libc_bitflags!{
++    /// Additional parameters for `mmap()`.
++    pub struct MapFlags: c_int {
++        /// Compatibility flag. Ignored.
++        MAP_FILE;
++        /// Share this mapping. Mutually exclusive with `MAP_PRIVATE`.
++        MAP_SHARED;
++        /// Create a private copy-on-write mapping. Mutually exclusive with `MAP_SHARED`.
++        MAP_PRIVATE;
++        /// Place the mapping at exactly the address specified in `addr`.
++        MAP_FIXED;
++        /// Synonym for `MAP_ANONYMOUS`.
++        MAP_ANON;
++        /// The mapping is not backed by any file.
++        #[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))]
++        MAP_ANONYMOUS;
++        /// Put the mapping into the first 2GB of the process address space.
++        #[cfg(any(all(any(target_os = "android", target_os = "linux"),
++                      any(target_arch = "x86", target_arch = "x86_64")),
++                  all(target_os = "linux", target_env = "musl", any(target_arch = "x86", target_arch = "x86_64")),
++                  all(target_os = "freebsd", target_pointer_width = "64")))]
++        MAP_32BIT;
++        /// Used for stacks; indicates to the kernel that the mapping should extend downward in memory.
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        MAP_GROWSDOWN;
++        /// Compatibility flag. Ignored.
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        MAP_DENYWRITE;
++        /// Compatibility flag. Ignored.
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        MAP_EXECUTABLE;
++        /// Mark the mmaped region to be locked in the same way as `mlock(2)`.
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        MAP_LOCKED;
++        /// Do not reserve swap space for this mapping.
++        ///
++        /// This was removed in FreeBSD 11.
++        #[cfg(not(target_os = "freebsd"))]
++        MAP_NORESERVE;
++        /// Populate page tables for a mapping.
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        MAP_POPULATE;
++        /// Only meaningful when used with `MAP_POPULATE`. Don't perform read-ahead.
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        MAP_NONBLOCK;
++        /// Allocate the mapping using "huge pages."
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        MAP_HUGETLB;
++        /// Lock the mapped region into memory as with `mlock(2)`.
++        #[cfg(target_os = "netbsd")]
++        MAP_WIRED;
++        /// Causes dirtied data in the specified range to be flushed to disk only when necessary.
++        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++        MAP_NOSYNC;
++        /// Rename private pages to a file.
++        ///
++        /// This was removed in FreeBSD 11.
++        #[cfg(any(target_os = "dragonfly", target_os = "netbsd", target_os = "openbsd"))]
++        MAP_RENAME;
++        /// Region may contain semaphores.
++        #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
++        MAP_HASSEMAPHORE;
++        /// Region grows down, like a stack.
++        #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
++        MAP_STACK;
++        /// Pages in this mapping are not retained in the kernel's memory cache.
++        #[cfg(any(target_os = "ios", target_os = "macos"))]
++        MAP_NOCACHE;
++        #[cfg(any(target_os = "ios", target_os = "macos"))]
++        MAP_JIT;
++    }
++}
++
++libc_enum!{
++    /// Usage information for a range of memory to allow for performance optimizations by the kernel.
++    ///
++    /// Used by [`madvise`](./fn.madvise.html).
++    #[repr(i32)]
++    pub enum MmapAdvise {
++        /// No further special treatment. This is the default.
++        MADV_NORMAL,
++        /// Expect random page references.
++        MADV_RANDOM,
++        /// Expect sequential page references.
++        MADV_SEQUENTIAL,
++        /// Expect access in the near future.
++        MADV_WILLNEED,
++        /// Do not expect access in the near future.
++        MADV_DONTNEED,
++        /// Free up a given range of pages and its associated backing store.
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        MADV_REMOVE,
++        /// Do not make pages in this range available to the child after a `fork(2)`.
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        MADV_DONTFORK,
++        /// Undo the effect of `MADV_DONTFORK`.
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        MADV_DOFORK,
++        /// Poison the given pages.
++        ///
++        /// Subsequent references to those pages are treated like hardware memory corruption.
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        MADV_HWPOISON,
++        /// Enable Kernel Samepage Merging (KSM) for the given pages.
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        MADV_MERGEABLE,
++        /// Undo the effect of `MADV_MERGEABLE`
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        MADV_UNMERGEABLE,
++        /// Preserve the memory of each page but offline the original page.
++        #[cfg(any(target_os = "android",
++            all(target_os = "linux", any(
++                target_arch = "aarch64",
++                target_arch = "arm",
++                target_arch = "ppc",
++                target_arch = "s390x",
++                target_arch = "x86",
++                target_arch = "x86_64",
++                target_arch = "sparc64"))))]
++        MADV_SOFT_OFFLINE,
++        /// Enable Transparent Huge Pages (THP) for pages in the given range.
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        MADV_HUGEPAGE,
++        /// Undo the effect of `MADV_HUGEPAGE`.
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        MADV_NOHUGEPAGE,
++        /// Exclude the given range from a core dump.
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        MADV_DONTDUMP,
++        /// Undo the effect of an earlier `MADV_DONTDUMP`.
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        MADV_DODUMP,
++        /// Specify that the application no longer needs the pages in the given range.
++        MADV_FREE,
++        /// Request that the system not flush the current range to disk unless it needs to.
++        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++        MADV_NOSYNC,
++        /// Undoes the effects of `MADV_NOSYNC` for any future pages dirtied within the given range.
++        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++        MADV_AUTOSYNC,
++        /// Region is not included in a core file.
++        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++        MADV_NOCORE,
++        /// Include region in a core file
++        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++        MADV_CORE,
++        #[cfg(any(target_os = "freebsd"))]
++        MADV_PROTECT,
++        /// Invalidate the hardware page table for the given region.
++        #[cfg(target_os = "dragonfly")]
++        MADV_INVAL,
++        /// Set the offset of the page directory page to `value` for the virtual page table.
++        #[cfg(target_os = "dragonfly")]
++        MADV_SETMAP,
++        /// Indicates that the application will not need the data in the given range.
++        #[cfg(any(target_os = "ios", target_os = "macos"))]
++        MADV_ZERO_WIRED_PAGES,
++        #[cfg(any(target_os = "ios", target_os = "macos"))]
++        MADV_FREE_REUSABLE,
++        #[cfg(any(target_os = "ios", target_os = "macos"))]
++        MADV_FREE_REUSE,
++        #[cfg(any(target_os = "ios", target_os = "macos"))]
++        MADV_CAN_REUSE,
++    }
++}
++
++libc_bitflags!{
++    /// Configuration flags for `msync`.
++    pub struct MsFlags: c_int {
++        /// Schedule an update but return immediately.
++        MS_ASYNC;
++        /// Invalidate all cached data.
++        MS_INVALIDATE;
++        /// Invalidate pages, but leave them mapped.
++        #[cfg(any(target_os = "ios", target_os = "macos"))]
++        MS_KILLPAGES;
++        /// Deactivate pages, but leave them mapped.
++        #[cfg(any(target_os = "ios", target_os = "macos"))]
++        MS_DEACTIVATE;
++        /// Perform an update and wait for it to complete.
++        MS_SYNC;
++    }
++}
++
++libc_bitflags!{
++    /// Flags for `mlockall`.
++    pub struct MlockAllFlags: c_int {
++        /// Lock pages that are currently mapped into the address space of the process.
++        MCL_CURRENT;
++        /// Lock pages which will become mapped into the address space of the process in the future.
++        MCL_FUTURE;
++    }
++}
++
++/// Locks all memory pages that contain part of the address range with `length` bytes starting at
++/// `addr`. Locked pages never move to the swap area.
++pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> {
++    Errno::result(libc::mlock(addr, length)).map(drop)
++}
++
++/// Unlocks all memory pages that contain part of the address range with `length` bytes starting at
++/// `addr`.
++pub unsafe fn munlock(addr: *const c_void, length: size_t) -> Result<()> {
++    Errno::result(libc::munlock(addr, length)).map(drop)
++}
++
++/// Locks all memory pages mapped into this process' address space. Locked pages never move to the
++/// swap area.
++pub fn mlockall(flags: MlockAllFlags) -> Result<()> {
++    unsafe { Errno::result(libc::mlockall(flags.bits())) }.map(drop)
++}
++
++/// Unlocks all memory pages mapped into this process' address space.
++pub fn munlockall() -> Result<()> {
++    unsafe { Errno::result(libc::munlockall()) }.map(drop)
++}
++
++/// Calls to mmap are inherently unsafe, so they must be made in an unsafe block. Typically
++/// a higher-level abstraction will hide the unsafe interactions with the mmap'd region.
++pub unsafe fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: MapFlags, fd: RawFd, offset: off_t) -> Result<*mut c_void> {
++    let ret = libc::mmap(addr, length, prot.bits(), flags.bits(), fd, offset);
++
++    if ret == libc::MAP_FAILED {
++        Err(Error::Sys(Errno::last()))
++    } else {
++        Ok(ret)
++    }
++}
++
++pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> {
++    Errno::result(libc::munmap(addr, len)).map(drop)
++}
++
++pub unsafe fn madvise(addr: *mut c_void, length: size_t, advise: MmapAdvise) -> Result<()> {
++    Errno::result(libc::madvise(addr, length, advise as i32)).map(drop)
++}
++
++/// Set protection of memory mapping.
++///
++/// See [`mprotect(3)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mprotect.html) for
++/// details.
++///
++/// # Safety
++///
++/// Calls to `mprotect` are inherently unsafe, as changes to memory protections can lead to
++/// SIGSEGVs.
++///
++/// ```
++/// # use nix::libc::size_t;
++/// # use nix::sys::mman::{mmap, mprotect, MapFlags, ProtFlags};
++/// # use std::ptr;
++/// const ONE_K: size_t = 1024;
++/// let mut slice: &mut [u8] = unsafe {
++///     let mem = mmap(ptr::null_mut(), ONE_K, ProtFlags::PROT_NONE,
++///                    MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, -1, 0).unwrap();
++///     mprotect(mem, ONE_K, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE).unwrap();
++///     std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K)
++/// };
++/// assert_eq!(slice[0], 0x00);
++/// slice[0] = 0xFF;
++/// assert_eq!(slice[0], 0xFF);
++/// ```
++pub unsafe fn mprotect(addr: *mut c_void, length: size_t, prot: ProtFlags) -> Result<()> {
++    Errno::result(libc::mprotect(addr, length, prot.bits())).map(drop)
++}
++
++pub unsafe fn msync(addr: *mut c_void, length: size_t, flags: MsFlags) -> Result<()> {
++    Errno::result(libc::msync(addr, length, flags.bits())).map(drop)
++}
++
++#[cfg(not(target_os = "android"))]
++pub fn shm_open<P: ?Sized + NixPath>(name: &P, flag: OFlag, mode: Mode) -> Result<RawFd> {
++    let ret = name.with_nix_path(|cstr| {
++        #[cfg(any(target_os = "macos", target_os = "ios"))]
++        unsafe {
++            libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::c_uint)
++        }
++        #[cfg(not(any(target_os = "macos", target_os = "ios")))]
++        unsafe {
++            libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::mode_t)
++        }
++    })?;
++
++    Errno::result(ret)
++}
++
++#[cfg(not(target_os = "android"))]
++pub fn shm_unlink<P: ?Sized + NixPath>(name: &P) -> Result<()> {
++    let ret = name.with_nix_path(|cstr| {
++        unsafe { libc::shm_unlink(cstr.as_ptr()) }
++    })?;
++
++    Errno::result(ret).map(drop)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/mod.rs b/third_party/rust/nix-0.15.0/src/sys/mod.rs
+new file mode 100644
+index 0000000000000..d3c2f92bbaaea
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/mod.rs
+@@ -0,0 +1,100 @@
++#[cfg(any(target_os = "dragonfly",
++          target_os = "freebsd",
++          target_os = "ios",
++          target_os = "linux",
++          target_os = "macos",
++          target_os = "netbsd"))]
++pub mod aio;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub mod epoll;
++
++#[cfg(any(target_os = "dragonfly",
++          target_os = "freebsd",
++          target_os = "ios",
++          target_os = "macos",
++          target_os = "netbsd",
++          target_os = "openbsd"))]
++pub mod event;
++
++#[cfg(target_os = "linux")]
++pub mod eventfd;
++
++#[cfg(any(target_os = "android",
++          target_os = "dragonfly",
++          target_os = "freebsd",
++          target_os = "ios",
++          target_os = "linux",
++          target_os = "macos",
++          target_os = "netbsd",
++          target_os = "openbsd"))]
++#[macro_use]
++pub mod ioctl;
++
++#[cfg(target_os = "linux")]
++pub mod memfd;
++
++pub mod mman;
++
++pub mod pthread;
++
++#[cfg(any(target_os = "android",
++          target_os = "dragonfly",
++          target_os = "freebsd",
++          target_os = "linux",
++          target_os = "macos",
++          target_os = "netbsd",
++          target_os = "openbsd"))]
++pub mod ptrace;
++
++#[cfg(target_os = "linux")]
++pub mod quota;
++
++#[cfg(any(target_os = "linux"))]
++pub mod reboot;
++
++pub mod select;
++
++#[cfg(any(target_os = "android",
++          target_os = "freebsd",
++          target_os = "ios",
++          target_os = "linux",
++          target_os = "macos"))]
++pub mod sendfile;
++
++pub mod signal;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub mod signalfd;
++
++pub mod socket;
++
++pub mod stat;
++
++#[cfg(any(target_os = "android",
++          target_os = "dragonfly",
++          target_os = "freebsd",
++          target_os = "ios",
++          target_os = "linux",
++          target_os = "macos",
++          target_os = "openbsd"
++))]
++pub mod statfs;
++
++pub mod statvfs;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub mod sysinfo;
++
++pub mod termios;
++
++pub mod time;
++
++pub mod uio;
++
++pub mod utsname;
++
++pub mod wait;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub mod inotify;
+diff --git a/third_party/rust/nix-0.15.0/src/sys/pthread.rs b/third_party/rust/nix-0.15.0/src/sys/pthread.rs
+new file mode 100644
+index 0000000000000..a4d98250f2b8b
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/pthread.rs
+@@ -0,0 +1,13 @@
++use libc::{self, pthread_t};
++
++pub type Pthread = pthread_t;
++
++/// Obtain ID of the calling thread (see
++/// [`pthread_self(3)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_self.html)
++///
++/// The thread ID returned by `pthread_self()` is not the same thing as
++/// the kernel thread ID returned by a call to `gettid(2)`.
++#[inline]
++pub fn pthread_self() -> Pthread {
++    unsafe { libc::pthread_self() }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/ptrace/bsd.rs b/third_party/rust/nix-0.15.0/src/sys/ptrace/bsd.rs
+new file mode 100644
+index 0000000000000..7797d10647ef4
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/ptrace/bsd.rs
+@@ -0,0 +1,170 @@
++use errno::Errno;
++use libc::{self, c_int};
++use std::ptr;
++use sys::signal::Signal;
++use unistd::Pid;
++use Result;
++
++pub type RequestType = c_int;
++
++cfg_if! {
++    if #[cfg(any(target_os = "dragonfly", 
++                 target_os = "freebsd", 
++                 target_os = "macos",
++                 target_os = "openbsd"))] {
++        #[doc(hidden)]
++        pub type AddressType = *mut ::libc::c_char;
++    } else {
++        #[doc(hidden)]
++        pub type AddressType = *mut ::libc::c_void;
++    }
++}
++
++libc_enum! {
++    #[repr(i32)]
++    /// Ptrace Request enum defining the action to be taken.
++    pub enum Request {
++        PT_TRACE_ME,
++        PT_READ_I,
++        PT_READ_D,
++        #[cfg(target_os = "macos")]
++        PT_READ_U,
++        PT_WRITE_I,
++        PT_WRITE_D,
++        #[cfg(target_os = "macos")]
++        PT_WRITE_U,
++        PT_CONTINUE,
++        PT_KILL,
++        #[cfg(any(any(target_os = "dragonfly",
++                  target_os = "freebsd",
++                  target_os = "macos"),
++                  all(target_os = "openbsd", target_arch = "x86_64"),
++                  all(target_os = "netbsd", any(target_arch = "x86_64",
++                                                target_arch = "powerpc"))))]
++        PT_STEP,
++        PT_ATTACH,
++        PT_DETACH,
++        #[cfg(target_os = "macos")]
++        PT_SIGEXC,
++        #[cfg(target_os = "macos")]
++        PT_THUPDATE,
++        #[cfg(target_os = "macos")]
++        PT_ATTACHEXC
++    }
++}
++
++unsafe fn ptrace_other(
++    request: Request,
++    pid: Pid,
++    addr: AddressType,
++    data: c_int,
++) -> Result<c_int> {
++    Errno::result(libc::ptrace(
++        request as RequestType,
++        libc::pid_t::from(pid),
++        addr,
++        data,
++    )).map(|_| 0)
++}
++
++/// Sets the process as traceable, as with `ptrace(PT_TRACEME, ...)`
++///
++/// Indicates that this process is to be traced by its parent.
++/// This is the only ptrace request to be issued by the tracee.
++pub fn traceme() -> Result<()> {
++    unsafe { ptrace_other(Request::PT_TRACE_ME, Pid::from_raw(0), ptr::null_mut(), 0).map(drop) }
++}
++
++/// Attach to a running process, as with `ptrace(PT_ATTACH, ...)`
++///
++/// Attaches to the process specified in pid, making it a tracee of the calling process.
++pub fn attach(pid: Pid) -> Result<()> {
++    unsafe { ptrace_other(Request::PT_ATTACH, pid, ptr::null_mut(), 0).map(drop) }
++}
++
++/// Detaches the current running process, as with `ptrace(PT_DETACH, ...)`
++///
++/// Detaches from the process specified in pid allowing it to run freely
++pub fn detach(pid: Pid) -> Result<()> {
++    unsafe { ptrace_other(Request::PT_DETACH, pid, ptr::null_mut(), 0).map(drop) }
++}
++
++/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)`
++///
++/// Continues the execution of the process with PID `pid`, optionally
++/// delivering a signal specified by `sig`.
++pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
++    let data = match sig.into() {
++        Some(s) => s as c_int,
++        None => 0,
++    };
++    unsafe {
++        // Ignore the useless return value
++        ptrace_other(Request::PT_CONTINUE, pid, 1 as AddressType, data).map(drop)
++    }
++}
++
++/// Issues a kill request as with `ptrace(PT_KILL, ...)`
++///
++/// This request is equivalent to `ptrace(PT_CONTINUE, ..., SIGKILL);` 
++pub fn kill(pid: Pid) -> Result<()> {
++    unsafe {
++        ptrace_other(Request::PT_KILL, pid, 0 as AddressType, 0).map(drop)
++    }
++}
++
++/// Move the stopped tracee process forward by a single step as with
++/// `ptrace(PT_STEP, ...)`
++///
++/// Advances the execution of the process with PID `pid` by a single step optionally delivering a
++/// signal specified by `sig`.
++///
++/// # Example
++/// ```rust
++/// extern crate nix;
++/// use nix::sys::ptrace::step;
++/// use nix::unistd::Pid;
++/// use nix::sys::signal::Signal;
++/// use nix::sys::wait::*;
++/// fn main() {
++///     // If a process changes state to the stopped state because of a SIGUSR1
++///     // signal, this will step the process forward and forward the user
++///     // signal to the stopped process
++///     match waitpid(Pid::from_raw(-1), None) {
++///         Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => {
++///             let _ = step(pid, Signal::SIGUSR1);
++///         }
++///         _ => {},
++///     }
++/// }
++/// ```
++#[cfg(
++    any(
++        any(target_os = "dragonfly", target_os = "freebsd", target_os = "macos"),
++        all(target_os = "openbsd", target_arch = "x86_64"),
++        all(target_os = "netbsd",
++            any(target_arch = "x86_64", target_arch = "powerpc")
++        )
++    )
++)]
++pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
++    let data = match sig.into() {
++        Some(s) => s as c_int,
++        None => 0,
++    };
++    unsafe { ptrace_other(Request::PT_STEP, pid, ptr::null_mut(), data).map(drop) }
++}
++
++/// Reads a word from a processes memory at the given address
++pub fn read(pid: Pid, addr: AddressType) -> Result<c_int> {
++    unsafe {
++        // Traditionally there was a difference between reading data or
++        // instruction memory but not in modern systems.
++        ptrace_other(Request::PT_READ_D, pid, addr, 0)
++    }
++}
++
++/// Writes a word into the processes memory at the given address
++pub fn write(pid: Pid, addr: AddressType, data: c_int) -> Result<()> {
++    unsafe { ptrace_other(Request::PT_WRITE_D, pid, addr, data).map(drop) }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/ptrace/linux.rs b/third_party/rust/nix-0.15.0/src/sys/ptrace/linux.rs
+new file mode 100644
+index 0000000000000..df15e66527562
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/ptrace/linux.rs
+@@ -0,0 +1,402 @@
++//! For detailed description of the ptrace requests, consult `man ptrace`.
++
++use std::{mem, ptr};
++use {Error, Result};
++use errno::Errno;
++use libc::{self, c_void, c_long, siginfo_t};
++use ::unistd::Pid;
++use sys::signal::Signal;
++
++pub type AddressType = *mut ::libc::c_void;
++
++#[cfg(all(target_os = "linux",
++          any(target_arch = "x86_64",
++              target_arch = "x86"),
++          target_env = "gnu"))]
++use libc::user_regs_struct;
++
++cfg_if! {
++    if #[cfg(any(all(target_os = "linux", target_arch = "s390x"),
++                 all(target_os = "linux", target_env = "gnu")))] {
++        #[doc(hidden)]
++        pub type RequestType = ::libc::c_uint;
++    } else {
++        #[doc(hidden)]
++        pub type RequestType = ::libc::c_int;
++    }
++}
++
++libc_enum!{
++    #[cfg_attr(not(any(target_env = "musl", target_os = "android")), repr(u32))]
++    #[cfg_attr(any(target_env = "musl", target_os = "android"), repr(i32))]
++    /// Ptrace Request enum defining the action to be taken.
++    pub enum Request {
++        PTRACE_TRACEME,
++        PTRACE_PEEKTEXT,
++        PTRACE_PEEKDATA,
++        PTRACE_PEEKUSER,
++        PTRACE_POKETEXT,
++        PTRACE_POKEDATA,
++        PTRACE_POKEUSER,
++        PTRACE_CONT,
++        PTRACE_KILL,
++        PTRACE_SINGLESTEP,
++        #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
++                  all(target_os = "linux", any(target_env = "musl",
++                                               target_arch = "mips",
++                                               target_arch = "mips64",
++                                               target_arch = "x86_64",
++                                               target_pointer_width = "32"))))]
++        PTRACE_GETREGS,
++        #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
++                  all(target_os = "linux", any(target_env = "musl",
++                                               target_arch = "mips",
++                                               target_arch = "mips64",
++                                               target_arch = "x86_64",
++                                               target_pointer_width = "32"))))]
++        PTRACE_SETREGS,
++        #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
++                  all(target_os = "linux", any(target_env = "musl",
++                                               target_arch = "mips",
++                                               target_arch = "mips64",
++                                               target_arch = "x86_64",
++                                               target_pointer_width = "32"))))]
++        PTRACE_GETFPREGS,
++        #[cfg(any(all(target_os = "android", target_pointer_width = "32"),
++                  all(target_os = "linux", any(target_env = "musl",
++                                               target_arch = "mips",
++                                               target_arch = "mips64",
++                                               target_arch = "x86_64",
++                                               target_pointer_width = "32"))))]
++        PTRACE_SETFPREGS,
++        PTRACE_ATTACH,
++        PTRACE_DETACH,
++        #[cfg(all(target_os = "linux", any(target_env = "musl",
++                                           target_arch = "mips",
++                                           target_arch = "mips64",
++                                           target_arch = "x86",
++                                           target_arch = "x86_64")))]
++        PTRACE_GETFPXREGS,
++        #[cfg(all(target_os = "linux", any(target_env = "musl",
++                                           target_arch = "mips",
++                                           target_arch = "mips64",
++                                           target_arch = "x86",
++                                           target_arch = "x86_64")))]
++        PTRACE_SETFPXREGS,
++        PTRACE_SYSCALL,
++        PTRACE_SETOPTIONS,
++        PTRACE_GETEVENTMSG,
++        PTRACE_GETSIGINFO,
++        PTRACE_SETSIGINFO,
++        #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
++                                               target_arch = "mips64"))))]
++        PTRACE_GETREGSET,
++        #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
++                                               target_arch = "mips64"))))]
++        PTRACE_SETREGSET,
++        #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
++                                               target_arch = "mips64"))))]
++        PTRACE_SEIZE,
++        #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
++                                               target_arch = "mips64"))))]
++        PTRACE_INTERRUPT,
++        #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
++                                               target_arch = "mips64"))))]
++        PTRACE_LISTEN,
++        #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
++                                               target_arch = "mips64"))))]
++        PTRACE_PEEKSIGINFO,
++    }
++}
++
++libc_enum!{
++    #[repr(i32)]
++    /// Using the ptrace options the tracer can configure the tracee to stop
++    /// at certain events. This enum is used to define those events as defined
++    /// in `man ptrace`.
++    pub enum Event {
++        /// Event that stops before a return from fork or clone.
++        PTRACE_EVENT_FORK,
++        /// Event that stops before a return from vfork or clone.
++        PTRACE_EVENT_VFORK,
++        /// Event that stops before a return from clone.
++        PTRACE_EVENT_CLONE,
++        /// Event that stops before a return from execve.
++        PTRACE_EVENT_EXEC,
++        /// Event for a return from vfork.
++        PTRACE_EVENT_VFORK_DONE,
++        /// Event for a stop before an exit. Unlike the waitpid Exit status program.
++        /// registers can still be examined
++        PTRACE_EVENT_EXIT,
++        /// STop triggered by a seccomp rule on a tracee.
++        PTRACE_EVENT_SECCOMP,
++        // PTRACE_EVENT_STOP not provided by libc because it's defined in glibc 2.26
++    }
++}
++
++libc_bitflags! {
++    /// Ptrace options used in conjunction with the PTRACE_SETOPTIONS request.
++    /// See `man ptrace` for more details.
++    pub struct Options: libc::c_int {
++        /// When delivering system call traps set a bit to allow tracer to
++        /// distinguish between normal stops or syscall stops. May not work on
++        /// all systems.
++        PTRACE_O_TRACESYSGOOD;
++        /// Stop tracee at next fork and start tracing the forked process.
++        PTRACE_O_TRACEFORK;
++        /// Stop tracee at next vfork call and trace the vforked process.
++        PTRACE_O_TRACEVFORK;
++        /// Stop tracee at next clone call and trace the cloned process.
++        PTRACE_O_TRACECLONE;
++        /// Stop tracee at next execve call.
++        PTRACE_O_TRACEEXEC;
++        /// Stop tracee at vfork completion.
++        PTRACE_O_TRACEVFORKDONE;
++        /// Stop tracee at next exit call. Stops before exit commences allowing
++        /// tracer to see location of exit and register states.
++        PTRACE_O_TRACEEXIT;
++        /// Stop tracee when a SECCOMP_RET_TRACE rule is triggered. See `man seccomp` for more
++        /// details.
++        PTRACE_O_TRACESECCOMP;
++        /// Send a SIGKILL to the tracee if the tracer exits.  This is useful
++        /// for ptrace jailers to prevent tracees from escaping their control.
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        PTRACE_O_EXITKILL;
++    }
++}
++
++/// Performs a ptrace request. If the request in question is provided by a specialised function
++/// this function will return an unsupported operation error.
++#[deprecated(
++    since="0.10.0",
++    note="usages of `ptrace()` should be replaced with the specialized helper functions instead"
++)]
++pub unsafe fn ptrace(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
++    use self::Request::*;
++    match request {
++        PTRACE_PEEKTEXT | PTRACE_PEEKDATA | PTRACE_GETSIGINFO | 
++            PTRACE_GETEVENTMSG | PTRACE_SETSIGINFO | PTRACE_SETOPTIONS | 
++            PTRACE_POKETEXT | PTRACE_POKEDATA | PTRACE_KILL => Err(Error::UnsupportedOperation),
++        _ => ptrace_other(request, pid, addr, data)
++    }
++}
++
++fn ptrace_peek(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
++    let ret = unsafe {
++        Errno::clear();
++        libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)
++    };
++    match Errno::result(ret) {
++        Ok(..) | Err(Error::Sys(Errno::UnknownErrno)) => Ok(ret),
++        err @ Err(..) => err,
++    }
++}
++
++/// Get user registers, as with `ptrace(PTRACE_GETREGS, ...)`
++#[cfg(all(target_os = "linux",
++          any(target_arch = "x86_64",
++              target_arch = "x86"),
++          target_env = "gnu"))]
++pub fn getregs(pid: Pid) -> Result<user_regs_struct> {
++    ptrace_get_data::<user_regs_struct>(Request::PTRACE_GETREGS, pid)
++}
++
++/// Set user registers, as with `ptrace(PTRACE_SETREGS, ...)`
++#[cfg(all(target_os = "linux",
++          any(target_arch = "x86_64",
++              target_arch = "x86"),
++          target_env = "gnu"))]
++pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
++    let res = unsafe {
++        libc::ptrace(Request::PTRACE_SETREGS as RequestType,
++                     libc::pid_t::from(pid),
++                     ptr::null_mut::<c_void>(),
++                     &regs as *const _ as *const c_void)
++    };
++    Errno::result(res).map(drop)
++}
++
++/// Function for ptrace requests that return values from the data field.
++/// Some ptrace get requests populate structs or larger elements than `c_long`
++/// and therefore use the data field to return values. This function handles these
++/// requests.
++fn ptrace_get_data<T>(request: Request, pid: Pid) -> Result<T> {
++    // Creates an uninitialized pointer to store result in
++    let data: T = unsafe { mem::uninitialized() };
++    let res = unsafe {
++        libc::ptrace(request as RequestType,
++                     libc::pid_t::from(pid),
++                     ptr::null_mut::<T>(),
++                     &data as *const _ as *const c_void)
++    };
++    Errno::result(res)?;
++    Ok(data)
++}
++
++unsafe fn ptrace_other(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
++    Errno::result(libc::ptrace(request as RequestType, libc::pid_t::from(pid), addr, data)).map(|_| 0)
++}
++
++/// Set options, as with `ptrace(PTRACE_SETOPTIONS,...)`.
++pub fn setoptions(pid: Pid, options: Options) -> Result<()> {
++    let res = unsafe {
++        libc::ptrace(Request::PTRACE_SETOPTIONS as RequestType,
++                     libc::pid_t::from(pid),
++                     ptr::null_mut::<c_void>(),
++                     options.bits() as *mut c_void)
++    };
++    Errno::result(res).map(drop)
++}
++
++/// Gets a ptrace event as described by `ptrace(PTRACE_GETEVENTMSG,...)`
++pub fn getevent(pid: Pid) -> Result<c_long> {
++    ptrace_get_data::<c_long>(Request::PTRACE_GETEVENTMSG, pid)
++}
++
++/// Get siginfo as with `ptrace(PTRACE_GETSIGINFO,...)`
++pub fn getsiginfo(pid: Pid) -> Result<siginfo_t> {
++    ptrace_get_data::<siginfo_t>(Request::PTRACE_GETSIGINFO, pid)
++}
++
++/// Set siginfo as with `ptrace(PTRACE_SETSIGINFO,...)`
++pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> {
++    let ret = unsafe{
++        Errno::clear();
++        libc::ptrace(Request::PTRACE_SETSIGINFO as RequestType,
++                     libc::pid_t::from(pid),
++                     ptr::null_mut::<c_void>(),
++                     sig as *const _ as *const c_void)
++    };
++    match Errno::result(ret) {
++        Ok(_) => Ok(()),
++        Err(e) => Err(e),
++    }
++}
++
++/// Sets the process as traceable, as with `ptrace(PTRACE_TRACEME, ...)`
++///
++/// Indicates that this process is to be traced by its parent.
++/// This is the only ptrace request to be issued by the tracee.
++pub fn traceme() -> Result<()> {
++    unsafe {
++        ptrace_other(
++            Request::PTRACE_TRACEME,
++            Pid::from_raw(0),
++            ptr::null_mut(),
++            ptr::null_mut(),
++        ).map(drop) // ignore the useless return value
++    }
++}
++
++/// Ask for next syscall, as with `ptrace(PTRACE_SYSCALL, ...)`
++///
++/// Arranges for the tracee to be stopped at the next entry to or exit from a system call.
++pub fn syscall(pid: Pid) -> Result<()> {
++    unsafe {
++        ptrace_other(
++            Request::PTRACE_SYSCALL,
++            pid,
++            ptr::null_mut(),
++            ptr::null_mut(),
++        ).map(drop) // ignore the useless return value
++    }
++}
++
++/// Attach to a running process, as with `ptrace(PTRACE_ATTACH, ...)`
++///
++/// Attaches to the process specified in pid, making it a tracee of the calling process.
++pub fn attach(pid: Pid) -> Result<()> {
++    unsafe {
++        ptrace_other(
++            Request::PTRACE_ATTACH,
++            pid,
++            ptr::null_mut(),
++            ptr::null_mut(),
++        ).map(drop) // ignore the useless return value
++    }
++}
++
++/// Detaches the current running process, as with `ptrace(PTRACE_DETACH, ...)`
++///
++/// Detaches from the process specified in pid allowing it to run freely
++pub fn detach(pid: Pid) -> Result<()> {
++    unsafe {
++        ptrace_other(
++            Request::PTRACE_DETACH,
++            pid,
++            ptr::null_mut(),
++            ptr::null_mut()
++        ).map(drop)
++    }
++}
++
++/// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)`
++///
++/// Continues the execution of the process with PID `pid`, optionally
++/// delivering a signal specified by `sig`.
++pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
++    let data = match sig.into() {
++        Some(s) => s as i32 as *mut c_void,
++        None => ptr::null_mut(),
++    };
++    unsafe {
++        ptrace_other(Request::PTRACE_CONT, pid, ptr::null_mut(), data).map(drop) // ignore the useless return value
++    }
++}
++
++/// Issues a kill request as with `ptrace(PTRACE_KILL, ...)`
++///
++/// This request is equivalent to `ptrace(PTRACE_CONT, ..., SIGKILL);`
++pub fn kill(pid: Pid) -> Result<()> {
++    unsafe {
++        ptrace_other(Request::PTRACE_KILL, pid, ptr::null_mut(), ptr::null_mut()).map(drop)
++    }
++}
++
++/// Move the stopped tracee process forward by a single step as with 
++/// `ptrace(PTRACE_SINGLESTEP, ...)`
++///
++/// Advances the execution of the process with PID `pid` by a single step optionally delivering a
++/// signal specified by `sig`.
++///
++/// # Example
++/// ```rust
++/// extern crate nix;
++/// use nix::sys::ptrace::step;
++/// use nix::unistd::Pid;
++/// use nix::sys::signal::Signal; 
++/// use nix::sys::wait::*;
++/// fn main() {
++///     // If a process changes state to the stopped state because of a SIGUSR1 
++///     // signal, this will step the process forward and forward the user 
++///     // signal to the stopped process
++///     match waitpid(Pid::from_raw(-1), None) {
++///         Ok(WaitStatus::Stopped(pid, Signal::SIGUSR1)) => {
++///             let _ = step(pid, Signal::SIGUSR1);
++///         }
++///         _ => {},
++///     }
++/// }
++/// ```
++pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
++    let data = match sig.into() {
++        Some(s) => s as i32 as *mut c_void,
++        None => ptr::null_mut(),
++    };
++    unsafe {
++        ptrace_other(Request::PTRACE_SINGLESTEP, pid, ptr::null_mut(), data).map(drop)
++    }
++}
++
++
++/// Reads a word from a processes memory at the given address
++pub fn read(pid: Pid, addr: AddressType) -> Result<c_long> {
++    ptrace_peek(Request::PTRACE_PEEKDATA, pid, addr, ptr::null_mut())
++}
++
++/// Writes a word into the processes memory at the given address
++pub fn write(pid: Pid, addr: AddressType, data: *mut c_void) -> Result<()> {
++    unsafe {
++        ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop)
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/ptrace/mod.rs b/third_party/rust/nix-0.15.0/src/sys/ptrace/mod.rs
+new file mode 100644
+index 0000000000000..782c30409bc12
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/ptrace/mod.rs
+@@ -0,0 +1,22 @@
++///! Provides helpers for making ptrace system calls 
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++mod linux;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub use self::linux::*;
++
++#[cfg(any(target_os = "dragonfly",
++          target_os = "freebsd",
++          target_os = "macos",
++          target_os = "netbsd",
++          target_os = "openbsd"))]
++mod bsd;
++
++#[cfg(any(target_os = "dragonfly",
++          target_os = "freebsd",
++          target_os = "macos",
++          target_os = "netbsd",
++          target_os = "openbsd"
++          ))]
++pub use self::bsd::*;
+diff --git a/third_party/rust/nix-0.15.0/src/sys/quota.rs b/third_party/rust/nix-0.15.0/src/sys/quota.rs
+new file mode 100644
+index 0000000000000..8946fca2213c8
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/quota.rs
+@@ -0,0 +1,273 @@
++//! Set and configure disk quotas for users, groups, or projects.
++//!
++//! # Examples
++//!
++//! Enabling and setting a quota:
++//!
++//! ```rust,no_run
++//! # use nix::sys::quota::{Dqblk, quotactl_on, quotactl_set, QuotaFmt, QuotaType, QuotaValidFlags};
++//! quotactl_on(QuotaType::USRQUOTA, "/dev/sda1", QuotaFmt::QFMT_VFS_V1, "aquota.user");
++//! let mut dqblk: Dqblk = Default::default();
++//! dqblk.set_blocks_hard_limit(10000);
++//! dqblk.set_blocks_soft_limit(8000);
++//! quotactl_set(QuotaType::USRQUOTA, "/dev/sda1", 50, &dqblk, QuotaValidFlags::QIF_BLIMITS);
++//! ```
++use std::default::Default;
++use std::{mem, ptr};
++use libc::{self, c_int, c_char};
++use {Result, NixPath};
++use errno::Errno;
++
++struct QuotaCmd(QuotaSubCmd, QuotaType);
++
++impl QuotaCmd {
++    fn as_int(&self) -> c_int {
++        unsafe { libc::QCMD(self.0 as i32, self.1 as i32) }
++    }
++}
++
++// linux quota version >= 2
++libc_enum!{
++    #[repr(i32)]
++    enum QuotaSubCmd {
++        Q_SYNC,
++        Q_QUOTAON,
++        Q_QUOTAOFF,
++        Q_GETQUOTA,
++        Q_SETQUOTA,
++    }
++}
++
++libc_enum!{
++    /// The scope of the quota.
++    #[repr(i32)]
++    pub enum QuotaType {
++        /// Specify a user quota
++        USRQUOTA,
++        /// Specify a group quota
++        GRPQUOTA,
++    }
++}
++
++libc_enum!{
++    /// The type of quota format to use.
++    #[repr(i32)]
++    pub enum QuotaFmt {
++        /// Use the original quota format.
++        QFMT_VFS_OLD,
++        /// Use the standard VFS v0 quota format.
++        ///
++        /// Handles 32-bit UIDs/GIDs and quota limits up to 2<sup>32</sup> bytes/2<sup>32</sup> inodes.
++        QFMT_VFS_V0,
++        /// Use the VFS v1 quota format.
++        ///
++        /// Handles 32-bit UIDs/GIDs and quota limits of 2<sup>64</sup> bytes/2<sup>64</sup> inodes.
++        QFMT_VFS_V1,
++    }
++}
++
++libc_bitflags!(
++    /// Indicates the quota fields that are valid to read from.
++    #[derive(Default)]
++    pub struct QuotaValidFlags: u32 {
++        /// The block hard & soft limit fields.
++        QIF_BLIMITS;
++        /// The current space field.
++        QIF_SPACE;
++        /// The inode hard & soft limit fields.
++        QIF_ILIMITS;
++        /// The current inodes field.
++        QIF_INODES;
++        /// The disk use time limit field.
++        QIF_BTIME;
++        /// The file quote time limit field.
++        QIF_ITIME;
++        /// All block & inode limits.
++        QIF_LIMITS;
++        /// The space & inodes usage fields.
++        QIF_USAGE;
++        /// The time limit fields.
++        QIF_TIMES;
++        /// All fields.
++        QIF_ALL;
++    }
++);
++
++/// Wrapper type for `if_dqblk`
++// FIXME: Change to repr(transparent)
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct Dqblk(libc::dqblk);
++
++impl Default for Dqblk {
++    fn default() -> Dqblk {
++        Dqblk(libc::dqblk {
++            dqb_bhardlimit: 0,
++            dqb_bsoftlimit: 0,
++            dqb_curspace: 0,
++            dqb_ihardlimit: 0,
++            dqb_isoftlimit: 0,
++            dqb_curinodes: 0,
++            dqb_btime: 0,
++            dqb_itime: 0,
++            dqb_valid: 0,
++        })
++    }
++}
++
++impl Dqblk {
++    /// The absolute limit on disk quota blocks allocated.
++    pub fn blocks_hard_limit(&self) -> Option<u64> {
++        let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
++        if valid_fields.contains(QuotaValidFlags::QIF_BLIMITS) {
++            Some(self.0.dqb_bhardlimit)
++        } else {
++            None
++        }
++    }
++
++    /// Set the absolute limit on disk quota blocks allocated.
++    pub fn set_blocks_hard_limit(&mut self, limit: u64) {
++        self.0.dqb_bhardlimit = limit;
++    }
++
++    /// Preferred limit on disk quota blocks
++    pub fn blocks_soft_limit(&self) -> Option<u64> {
++        let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
++        if valid_fields.contains(QuotaValidFlags::QIF_BLIMITS) {
++            Some(self.0.dqb_bsoftlimit)
++        } else {
++            None
++        }
++    }
++
++    /// Set the preferred limit on disk quota blocks allocated.
++    pub fn set_blocks_soft_limit(&mut self, limit: u64) {
++        self.0.dqb_bsoftlimit = limit;
++    }
++
++    /// Current occupied space (bytes).
++    pub fn occupied_space(&self) -> Option<u64> {
++        let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
++        if valid_fields.contains(QuotaValidFlags::QIF_SPACE) {
++            Some(self.0.dqb_curspace)
++        } else {
++            None
++        }
++    }
++
++    /// Maximum number of allocated inodes.
++    pub fn inodes_hard_limit(&self) -> Option<u64> {
++        let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
++        if valid_fields.contains(QuotaValidFlags::QIF_ILIMITS) {
++            Some(self.0.dqb_ihardlimit)
++        } else {
++            None
++        }
++    }
++
++    /// Set the maximum number of allocated inodes.
++    pub fn set_inodes_hard_limit(&mut self, limit: u64) {
++        self.0.dqb_ihardlimit = limit;
++    }
++
++    /// Preferred inode limit
++    pub fn inodes_soft_limit(&self) -> Option<u64> {
++        let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
++        if valid_fields.contains(QuotaValidFlags::QIF_ILIMITS) {
++            Some(self.0.dqb_isoftlimit)
++        } else {
++            None
++        }
++    }
++
++    /// Set the preferred limit of allocated inodes.
++    pub fn set_inodes_soft_limit(&mut self, limit: u64) {
++        self.0.dqb_isoftlimit = limit;
++    }
++
++    /// Current number of allocated inodes.
++    pub fn allocated_inodes(&self) -> Option<u64> {
++        let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
++        if valid_fields.contains(QuotaValidFlags::QIF_INODES) {
++            Some(self.0.dqb_curinodes)
++        } else {
++            None
++        }
++    }
++
++    /// Time limit for excessive disk use.
++    pub fn block_time_limit(&self) -> Option<u64> {
++        let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
++        if valid_fields.contains(QuotaValidFlags::QIF_BTIME) {
++            Some(self.0.dqb_btime)
++        } else {
++            None
++        }
++    }
++
++    /// Set the time limit for excessive disk use.
++    pub fn set_block_time_limit(&mut self, limit: u64) {
++        self.0.dqb_btime = limit;
++    }
++
++    /// Time limit for excessive files.
++    pub fn inode_time_limit(&self) -> Option<u64> {
++        let valid_fields = QuotaValidFlags::from_bits_truncate(self.0.dqb_valid);
++        if valid_fields.contains(QuotaValidFlags::QIF_ITIME) {
++            Some(self.0.dqb_itime)
++        } else {
++            None
++        }
++    }
++
++    /// Set the time limit for excessive files.
++    pub fn set_inode_time_limit(&mut self, limit: u64) {
++        self.0.dqb_itime = limit;
++    }
++}
++
++fn quotactl<P: ?Sized + NixPath>(cmd: QuotaCmd, special: Option<&P>, id: c_int, addr: *mut c_char) -> Result<()> {
++    unsafe {
++        Errno::clear();
++        let res = match special {
++            Some(dev) => dev.with_nix_path(|path| libc::quotactl(cmd.as_int(), path.as_ptr(), id, addr)),
++            None => Ok(libc::quotactl(cmd.as_int(), ptr::null(), id, addr)),
++        }?;
++
++        Errno::result(res).map(drop)
++    }
++}
++
++/// Turn on disk quotas for a block device.
++pub fn quotactl_on<P: ?Sized + NixPath>(which: QuotaType, special: &P, format: QuotaFmt, quota_file: &P) -> Result<()> {
++    quota_file.with_nix_path(|path| {
++        let mut path_copy = path.to_bytes_with_nul().to_owned();
++        let p: *mut c_char = path_copy.as_mut_ptr() as *mut c_char;
++        quotactl(QuotaCmd(QuotaSubCmd::Q_QUOTAON, which), Some(special), format as c_int, p)
++    })?
++}
++
++/// Disable disk quotas for a block device.
++pub fn quotactl_off<P: ?Sized + NixPath>(which: QuotaType, special: &P) -> Result<()> {
++    quotactl(QuotaCmd(QuotaSubCmd::Q_QUOTAOFF, which), Some(special), 0, ptr::null_mut())
++}
++
++/// Update the on-disk copy of quota usages for a filesystem.
++pub fn quotactl_sync<P: ?Sized + NixPath>(which: QuotaType, special: Option<&P>) -> Result<()> {
++    quotactl(QuotaCmd(QuotaSubCmd::Q_SYNC, which), special, 0, ptr::null_mut())
++}
++
++/// Get disk quota limits and current usage for the given user/group id.
++pub fn quotactl_get<P: ?Sized + NixPath>(which: QuotaType, special: &P, id: c_int) -> Result<Dqblk> {
++    let mut dqblk = unsafe { mem::uninitialized() };
++    quotactl(QuotaCmd(QuotaSubCmd::Q_GETQUOTA, which), Some(special), id, &mut dqblk as *mut _ as *mut c_char)?;
++    dqblk
++}
++
++/// Configure quota values for the specified fields for a given user/group id.
++pub fn quotactl_set<P: ?Sized + NixPath>(which: QuotaType, special: &P, id: c_int, dqblk: &Dqblk, fields: QuotaValidFlags) -> Result<()> {
++    let mut dqblk_copy = *dqblk;
++    dqblk_copy.0.dqb_valid = fields.bits();
++    quotactl(QuotaCmd(QuotaSubCmd::Q_SETQUOTA, which), Some(special), id, &mut dqblk_copy as *mut _ as *mut c_char)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/reboot.rs b/third_party/rust/nix-0.15.0/src/sys/reboot.rs
+new file mode 100644
+index 0000000000000..bafa8fc11996d
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/reboot.rs
+@@ -0,0 +1,45 @@
++//! Reboot/shutdown or enable/disable Ctrl-Alt-Delete.
++
++use {Error, Result};
++use errno::Errno;
++use libc;
++use void::Void;
++use std::mem::drop;
++
++libc_enum! {
++    /// How exactly should the system be rebooted.
++    ///
++    /// See [`set_cad_enabled()`](fn.set_cad_enabled.html) for
++    /// enabling/disabling Ctrl-Alt-Delete.
++    #[repr(i32)]
++    pub enum RebootMode {
++        RB_HALT_SYSTEM,
++        RB_KEXEC,
++        RB_POWER_OFF,
++        RB_AUTOBOOT,
++        // we do not support Restart2,
++        RB_SW_SUSPEND,
++    }
++}
++
++pub fn reboot(how: RebootMode) -> Result<Void> {
++    unsafe {
++        libc::reboot(how as libc::c_int)
++    };
++    Err(Error::Sys(Errno::last()))
++}
++
++/// Enable or disable the reboot keystroke (Ctrl-Alt-Delete).
++///
++/// Corresponds to calling `reboot(RB_ENABLE_CAD)` or `reboot(RB_DISABLE_CAD)` in C.
++pub fn set_cad_enabled(enable: bool) -> Result<()> {
++    let cmd = if enable {
++        libc::RB_ENABLE_CAD
++    } else {
++        libc::RB_DISABLE_CAD
++    };
++    let res = unsafe {
++        libc::reboot(cmd)
++    };
++    Errno::result(res).map(drop)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/select.rs b/third_party/rust/nix-0.15.0/src/sys/select.rs
+new file mode 100644
+index 0000000000000..1b518e29f67a6
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/select.rs
+@@ -0,0 +1,334 @@
++use std::mem;
++use std::os::unix::io::RawFd;
++use std::ptr::{null, null_mut};
++use libc::{self, c_int};
++use Result;
++use errno::Errno;
++use sys::signal::SigSet;
++use sys::time::{TimeSpec, TimeVal};
++
++pub use libc::FD_SETSIZE;
++
++// FIXME: Change to repr(transparent) once it's stable
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct FdSet(libc::fd_set);
++
++impl FdSet {
++    pub fn new() -> FdSet {
++        let mut fdset = unsafe { mem::uninitialized() };
++        unsafe { libc::FD_ZERO(&mut fdset) };
++        FdSet(fdset)
++    }
++
++    pub fn insert(&mut self, fd: RawFd) {
++        unsafe { libc::FD_SET(fd, &mut self.0) };
++    }
++
++    pub fn remove(&mut self, fd: RawFd) {
++        unsafe { libc::FD_CLR(fd, &mut self.0) };
++    }
++
++    pub fn contains(&mut self, fd: RawFd) -> bool {
++        unsafe { libc::FD_ISSET(fd, &mut self.0) }
++    }
++
++    pub fn clear(&mut self) {
++        unsafe { libc::FD_ZERO(&mut self.0) };
++    }
++
++    /// Finds the highest file descriptor in the set.
++    ///
++    /// Returns `None` if the set is empty.
++    ///
++    /// This can be used to calculate the `nfds` parameter of the [`select`] function.
++    ///
++    /// # Example
++    ///
++    /// ```
++    /// # extern crate nix;
++    /// # use nix::sys::select::FdSet;
++    /// # fn main() {
++    /// let mut set = FdSet::new();
++    /// set.insert(4);
++    /// set.insert(9);
++    /// assert_eq!(set.highest(), Some(9));
++    /// # }
++    /// ```
++    ///
++    /// [`select`]: fn.select.html
++    pub fn highest(&mut self) -> Option<RawFd> {
++        for i in (0..FD_SETSIZE).rev() {
++            let i = i as RawFd;
++            if unsafe { libc::FD_ISSET(i, self as *mut _ as *mut libc::fd_set) } {
++                return Some(i)
++            }
++        }
++
++        None
++    }
++}
++
++/// Monitors file descriptors for readiness
++///
++/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all
++/// file descriptors that are ready for the given operation are set.
++///
++/// When this function returns, `timeout` has an implementation-defined value.
++///
++/// # Parameters
++///
++/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this
++///   is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1
++///   to the maximum of that.
++/// * `readfds`: File descriptors to check for being ready to read.
++/// * `writefds`: File descriptors to check for being ready to write.
++/// * `errorfds`: File descriptors to check for pending error conditions.
++/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block
++///   indefinitely).
++///
++/// # References
++///
++/// [select(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html)
++///
++/// [`FdSet::highest`]: struct.FdSet.html#method.highest
++pub fn select<'a, N, R, W, E, T>(nfds: N,
++                                 readfds: R,
++                                 writefds: W,
++                                 errorfds: E,
++                                 timeout: T) -> Result<c_int>
++where
++    N: Into<Option<c_int>>,
++    R: Into<Option<&'a mut FdSet>>,
++    W: Into<Option<&'a mut FdSet>>,
++    E: Into<Option<&'a mut FdSet>>,
++    T: Into<Option<&'a mut TimeVal>>,
++{
++    let mut readfds = readfds.into();
++    let mut writefds = writefds.into();
++    let mut errorfds = errorfds.into();
++    let timeout = timeout.into();
++
++    let nfds = nfds.into().unwrap_or_else(|| {
++        readfds.iter_mut()
++            .chain(writefds.iter_mut())
++            .chain(errorfds.iter_mut())
++            .map(|set| set.highest().unwrap_or(-1))
++            .max()
++            .unwrap_or(-1) + 1
++    });
++
++    let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
++    let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
++    let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
++    let timeout = timeout.map(|tv| tv as *mut _ as *mut libc::timeval)
++                         .unwrap_or(null_mut());
++
++    let res = unsafe {
++        libc::select(nfds, readfds, writefds, errorfds, timeout)
++    };
++
++    Errno::result(res)
++}
++
++/// Monitors file descriptors for readiness with an altered signal mask.
++///
++/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all
++/// file descriptors that are ready for the given operation are set.
++///
++/// When this function returns, the original signal mask is restored.
++///
++/// Unlike [`select`](#fn.select), `pselect` does not mutate the `timeout` value.
++///
++/// # Parameters
++///
++/// * `nfds`: The highest file descriptor set in any of the passed `FdSet`s, plus 1. If `None`, this
++///   is calculated automatically by calling [`FdSet::highest`] on all descriptor sets and adding 1
++///   to the maximum of that.
++/// * `readfds`: File descriptors to check for read readiness
++/// * `writefds`: File descriptors to check for write readiness
++/// * `errorfds`: File descriptors to check for pending error conditions.
++/// * `timeout`: Maximum time to wait for descriptors to become ready (`None` to block
++///   indefinitely).
++/// * `sigmask`: Signal mask to activate while waiting for file descriptors to turn
++///    ready (`None` to set no alternative signal mask).
++///
++/// # References
++///
++/// [pselect(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pselect.html)
++///
++/// [The new pselect() system call](https://lwn.net/Articles/176911/)
++///
++/// [`FdSet::highest`]: struct.FdSet.html#method.highest
++pub fn pselect<'a, N, R, W, E, T, S>(nfds: N,
++                                     readfds: R,
++                                     writefds: W,
++                                     errorfds: E,
++                                     timeout: T,
++                                     sigmask: S) -> Result<c_int>
++where
++    N: Into<Option<c_int>>,
++    R: Into<Option<&'a mut FdSet>>,
++    W: Into<Option<&'a mut FdSet>>,
++    E: Into<Option<&'a mut FdSet>>,
++    T: Into<Option<&'a TimeSpec>>,
++    S: Into<Option<&'a SigSet>>,
++{
++    let mut readfds = readfds.into();
++    let mut writefds = writefds.into();
++    let mut errorfds = errorfds.into();
++    let sigmask = sigmask.into();
++    let timeout = timeout.into();
++
++    let nfds = nfds.into().unwrap_or_else(|| {
++        readfds.iter_mut()
++            .chain(writefds.iter_mut())
++            .chain(errorfds.iter_mut())
++            .map(|set| set.highest().unwrap_or(-1))
++            .max()
++            .unwrap_or(-1) + 1
++    });
++
++    let readfds = readfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
++    let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
++    let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
++    let timeout = timeout.map(|ts| ts.as_ref() as *const libc::timespec).unwrap_or(null());
++    let sigmask = sigmask.map(|sm| sm.as_ref() as *const libc::sigset_t).unwrap_or(null());
++
++    let res = unsafe {
++        libc::pselect(nfds, readfds, writefds, errorfds, timeout, sigmask)
++    };
++
++    Errno::result(res)
++}
++
++
++#[cfg(test)]
++mod tests {
++    use super::*;
++    use std::os::unix::io::RawFd;
++    use sys::time::{TimeVal, TimeValLike};
++    use unistd::{write, pipe};
++
++    #[test]
++    fn fdset_insert() {
++        let mut fd_set = FdSet::new();
++
++        for i in 0..FD_SETSIZE {
++            assert!(!fd_set.contains(i as RawFd));
++        }
++
++        fd_set.insert(7);
++
++        assert!(fd_set.contains(7));
++    }
++
++    #[test]
++    fn fdset_remove() {
++        let mut fd_set = FdSet::new();
++
++        for i in 0..FD_SETSIZE {
++            assert!(!fd_set.contains(i as RawFd));
++        }
++
++        fd_set.insert(7);
++        fd_set.remove(7);
++
++        for i in 0..FD_SETSIZE {
++            assert!(!fd_set.contains(i as RawFd));
++        }
++    }
++
++    #[test]
++    fn fdset_clear() {
++        let mut fd_set = FdSet::new();
++        fd_set.insert(1);
++        fd_set.insert((FD_SETSIZE / 2) as RawFd);
++        fd_set.insert((FD_SETSIZE - 1) as RawFd);
++
++        fd_set.clear();
++
++        for i in 0..FD_SETSIZE {
++            assert!(!fd_set.contains(i as RawFd));
++        }
++    }
++
++    #[test]
++    fn fdset_highest() {
++        let mut set = FdSet::new();
++        assert_eq!(set.highest(), None);
++        set.insert(0);
++        assert_eq!(set.highest(), Some(0));
++        set.insert(90);
++        assert_eq!(set.highest(), Some(90));
++        set.remove(0);
++        assert_eq!(set.highest(), Some(90));
++        set.remove(90);
++        assert_eq!(set.highest(), None);
++
++        set.insert(4);
++        set.insert(5);
++        set.insert(7);
++        assert_eq!(set.highest(), Some(7));
++    }
++
++    #[test]
++    fn test_select() {
++        let (r1, w1) = pipe().unwrap();
++        write(w1, b"hi!").unwrap();
++        let (r2, _w2) = pipe().unwrap();
++
++        let mut fd_set = FdSet::new();
++        fd_set.insert(r1);
++        fd_set.insert(r2);
++
++        let mut timeout = TimeVal::seconds(10);
++        assert_eq!(1, select(None,
++                             &mut fd_set,
++                             None,
++                             None,
++                             &mut timeout).unwrap());
++        assert!(fd_set.contains(r1));
++        assert!(!fd_set.contains(r2));
++    }
++
++    #[test]
++    fn test_select_nfds() {
++        let (r1, w1) = pipe().unwrap();
++        write(w1, b"hi!").unwrap();
++        let (r2, _w2) = pipe().unwrap();
++
++        let mut fd_set = FdSet::new();
++        fd_set.insert(r1);
++        fd_set.insert(r2);
++
++        let mut timeout = TimeVal::seconds(10);
++        assert_eq!(1, select(Some(fd_set.highest().unwrap() + 1),
++                             &mut fd_set,
++                             None,
++                             None,
++                             &mut timeout).unwrap());
++        assert!(fd_set.contains(r1));
++        assert!(!fd_set.contains(r2));
++    }
++
++    #[test]
++    fn test_select_nfds2() {
++        let (r1, w1) = pipe().unwrap();
++        write(w1, b"hi!").unwrap();
++        let (r2, _w2) = pipe().unwrap();
++
++        let mut fd_set = FdSet::new();
++        fd_set.insert(r1);
++        fd_set.insert(r2);
++
++        let mut timeout = TimeVal::seconds(10);
++        assert_eq!(1, select(::std::cmp::max(r1, r2) + 1,
++                             &mut fd_set,
++                             None,
++                             None,
++                             &mut timeout).unwrap());
++        assert!(fd_set.contains(r1));
++        assert!(!fd_set.contains(r2));
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/sendfile.rs b/third_party/rust/nix-0.15.0/src/sys/sendfile.rs
+new file mode 100644
+index 0000000000000..a47d8962f73fb
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/sendfile.rs
+@@ -0,0 +1,200 @@
++use std::os::unix::io::RawFd;
++use std::ptr;
++
++use libc::{self, off_t};
++
++use Result;
++use errno::Errno;
++
++/// Copy up to `count` bytes to `out_fd` from `in_fd` starting at `offset`.
++///
++/// Returns a `Result` with the number of bytes written.
++///
++/// If `offset` is `None`, `sendfile` will begin reading at the current offset of `in_fd`and will
++/// update the offset of `in_fd`. If `offset` is `Some`, `sendfile` will begin at the specified
++/// offset and will not update the offset of `in_fd`. Instead, it will mutate `offset` to point to
++/// the byte after the last byte copied.
++///
++/// `in_fd` must support `mmap`-like operations and therefore cannot be a socket.
++///
++/// For more information, see [the sendfile(2) man page.](http://man7.org/linux/man-pages/man2/sendfile.2.html)
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub fn sendfile(
++    out_fd: RawFd,
++    in_fd: RawFd,
++    offset: Option<&mut off_t>,
++    count: usize,
++) -> Result<usize> {
++    let offset = offset
++        .map(|offset| offset as *mut _)
++        .unwrap_or(ptr::null_mut());
++    let ret = unsafe { libc::sendfile(out_fd, in_fd, offset, count) };
++    Errno::result(ret).map(|r| r as usize)
++}
++
++cfg_if! {
++    if #[cfg(any(target_os = "freebsd",
++                 target_os = "ios",
++                 target_os = "macos"))] {
++        use sys::uio::IoVec;
++
++        #[derive(Clone, Debug, Eq, Hash, PartialEq)]
++        struct SendfileHeaderTrailer<'a>(
++            libc::sf_hdtr,
++            Option<Vec<IoVec<&'a [u8]>>>,
++            Option<Vec<IoVec<&'a [u8]>>>,
++        );
++
++        impl<'a> SendfileHeaderTrailer<'a> {
++            fn new(
++                headers: Option<&'a [&'a [u8]]>,
++                trailers: Option<&'a [&'a [u8]]>
++            ) -> SendfileHeaderTrailer<'a> {
++                let header_iovecs: Option<Vec<IoVec<&[u8]>>> =
++                    headers.map(|s| s.iter().map(|b| IoVec::from_slice(b)).collect());
++                let trailer_iovecs: Option<Vec<IoVec<&[u8]>>> =
++                    trailers.map(|s| s.iter().map(|b| IoVec::from_slice(b)).collect());
++                SendfileHeaderTrailer(
++                    libc::sf_hdtr {
++                        headers: {
++                            header_iovecs
++                                .as_ref()
++                                .map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec
++                        },
++                        hdr_cnt: header_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32,
++                        trailers: {
++                            trailer_iovecs
++                                .as_ref()
++                                .map_or(ptr::null(), |v| v.as_ptr()) as *mut libc::iovec
++                        },
++                        trl_cnt: trailer_iovecs.as_ref().map(|v| v.len()).unwrap_or(0) as i32
++                    },
++                    header_iovecs,
++                    trailer_iovecs,
++                )
++            }
++        }
++    }
++}
++
++cfg_if! {
++    if #[cfg(target_os = "freebsd")] {
++        use libc::c_int;
++
++        libc_bitflags!{
++            /// Configuration options for [`sendfile`.](fn.sendfile.html)
++            pub struct SfFlags: c_int {
++                /// Causes `sendfile` to return EBUSY instead of blocking when attempting to read a
++                /// busy page.
++                SF_NODISKIO;
++                /// Causes `sendfile` to sleep until the network stack releases its reference to the
++                /// VM pages read. When `sendfile` returns, the data is not guaranteed to have been
++                /// sent, but it is safe to modify the file.
++                SF_SYNC;
++                /// Causes `sendfile` to cache exactly the number of pages specified in the
++                /// `readahead` parameter, disabling caching heuristics.
++                SF_USER_READAHEAD;
++                /// Causes `sendfile` not to cache the data read.
++                SF_NOCACHE;
++            }
++        }
++
++        /// Read up to `count` bytes from `in_fd` starting at `offset` and write to `out_sock`.
++        ///
++        /// Returns a `Result` and a count of bytes written. Bytes written may be non-zero even if
++        /// an error occurs.
++        ///
++        /// `in_fd` must describe a regular file or shared memory object. `out_sock` must describe a
++        /// stream socket.
++        ///
++        /// If `offset` falls past the end of the file, the function returns success and zero bytes
++        /// written.
++        ///
++        /// If `count` is `None` or 0, bytes will be read from `in_fd` until reaching the end of
++        /// file (EOF).
++        ///
++        /// `headers` and `trailers` specify optional slices of byte slices to be sent before and
++        /// after the data read from `in_fd`, respectively. The length of headers and trailers sent
++        /// is included in the returned count of bytes written. The values of `offset` and `count`
++        /// do not apply to headers or trailers.
++        ///
++        /// `readahead` specifies the minimum number of pages to cache in memory ahead of the page
++        /// currently being sent.
++        ///
++        /// For more information, see
++        /// [the sendfile(2) man page.](https://www.freebsd.org/cgi/man.cgi?query=sendfile&sektion=2)
++        pub fn sendfile(
++            in_fd: RawFd,
++            out_sock: RawFd,
++            offset: off_t,
++            count: Option<usize>,
++            headers: Option<&[&[u8]]>,
++            trailers: Option<&[&[u8]]>,
++            flags: SfFlags,
++            readahead: u16
++        ) -> (Result<()>, off_t) {
++            // Readahead goes in upper 16 bits
++            // Flags goes in lower 16 bits
++            // see `man 2 sendfile`
++            let flags: u32 = ((readahead as u32) << 16) | (flags.bits() as u32);
++            let mut bytes_sent: off_t = 0;
++            let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
++            let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr);
++            let return_code = unsafe {
++                libc::sendfile(in_fd,
++                               out_sock,
++                               offset,
++                               count.unwrap_or(0),
++                               hdtr_ptr as *mut libc::sf_hdtr,
++                               &mut bytes_sent as *mut off_t,
++                               flags as c_int)
++            };
++            (Errno::result(return_code).and(Ok(())), bytes_sent)
++        }
++    } else if #[cfg(any(target_os = "ios", target_os = "macos"))] {
++        /// Read bytes from `in_fd` starting at `offset` and write up to `count` bytes to
++        /// `out_sock`.
++        ///
++        /// Returns a `Result` and a count of bytes written. Bytes written may be non-zero even if
++        /// an error occurs.
++        ///
++        /// `in_fd` must describe a regular file. `out_sock` must describe a stream socket.
++        ///
++        /// If `offset` falls past the end of the file, the function returns success and zero bytes
++        /// written.
++        ///
++        /// If `count` is `None` or 0, bytes will be read from `in_fd` until reaching the end of
++        /// file (EOF).
++        ///
++        /// `hdtr` specifies an optional list of headers and trailers to be sent before and after
++        /// the data read from `in_fd`, respectively. The length of headers and trailers sent is
++        /// included in the returned count of bytes written. If any headers are specified and
++        /// `count` is non-zero, the length of the headers will be counted in the limit of total
++        /// bytes sent. Trailers do not count toward the limit of bytes sent and will always be sent
++        /// regardless. The value of `offset` does not affect headers or trailers.
++        ///
++        /// For more information, see
++        /// [the sendfile(2) man page.](https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man2/sendfile.2.html)
++        pub fn sendfile(
++            in_fd: RawFd,
++            out_sock: RawFd,
++            offset: off_t,
++            count: Option<off_t>,
++            headers: Option<&[&[u8]]>,
++            trailers: Option<&[&[u8]]>
++        ) -> (Result<()>, off_t) {
++            let mut len = count.unwrap_or(0);
++            let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
++            let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr);
++            let return_code = unsafe {
++                libc::sendfile(in_fd,
++                               out_sock,
++                               offset,
++                               &mut len as *mut off_t,
++                               hdtr_ptr as *mut libc::sf_hdtr,
++                               0)
++            };
++            (Errno::result(return_code).and(Ok(())), len)
++        }
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/signal.rs b/third_party/rust/nix-0.15.0/src/sys/signal.rs
+new file mode 100644
+index 0000000000000..1013a77fd4b40
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/signal.rs
+@@ -0,0 +1,966 @@
++// Portions of this file are Copyright 2014 The Rust Project Developers.
++// See http://rust-lang.org/COPYRIGHT.
++
++///! Operating system signals.
++
++use libc;
++use {Error, Result};
++use errno::Errno;
++use std::mem;
++use std::fmt;
++use std::str::FromStr;
++#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++use std::os::unix::io::RawFd;
++use std::ptr;
++
++#[cfg(not(target_os = "openbsd"))]
++pub use self::sigevent::*;
++
++libc_enum!{
++    // Currently there is only one definition of c_int in libc, as well as only one
++    // type for signal constants.
++    // We would prefer to use the libc::c_int alias in the repr attribute. Unfortunately
++    // this is not (yet) possible.
++    #[repr(i32)]
++    pub enum Signal {
++        SIGHUP,
++        SIGINT,
++        SIGQUIT,
++        SIGILL,
++        SIGTRAP,
++        SIGABRT,
++        SIGBUS,
++        SIGFPE,
++        SIGKILL,
++        SIGUSR1,
++        SIGSEGV,
++        SIGUSR2,
++        SIGPIPE,
++        SIGALRM,
++        SIGTERM,
++        #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
++                  not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
++        SIGSTKFLT,
++        SIGCHLD,
++        SIGCONT,
++        SIGSTOP,
++        SIGTSTP,
++        SIGTTIN,
++        SIGTTOU,
++        SIGURG,
++        SIGXCPU,
++        SIGXFSZ,
++        SIGVTALRM,
++        SIGPROF,
++        SIGWINCH,
++        SIGIO,
++        #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
++        SIGPWR,
++        SIGSYS,
++        #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
++        SIGEMT,
++        #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
++        SIGINFO,
++    }
++}
++
++impl FromStr for Signal {
++    type Err = Error;
++    fn from_str(s: &str) -> Result<Signal> {
++        Ok(match s {
++            "SIGHUP" => Signal::SIGHUP,
++            "SIGINT" => Signal::SIGINT,
++            "SIGQUIT" => Signal::SIGQUIT,
++            "SIGILL" => Signal::SIGILL,
++            "SIGTRAP" => Signal::SIGTRAP,
++            "SIGABRT" => Signal::SIGABRT,
++            "SIGBUS" => Signal::SIGBUS,
++            "SIGFPE" => Signal::SIGFPE,
++            "SIGKILL" => Signal::SIGKILL,
++            "SIGUSR1" => Signal::SIGUSR1,
++            "SIGSEGV" => Signal::SIGSEGV,
++            "SIGUSR2" => Signal::SIGUSR2,
++            "SIGPIPE" => Signal::SIGPIPE,
++            "SIGALRM" => Signal::SIGALRM,
++            "SIGTERM" => Signal::SIGTERM,
++            #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
++                      not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
++            "SIGSTKFLT" => Signal::SIGSTKFLT,
++            "SIGCHLD" => Signal::SIGCHLD,
++            "SIGCONT" => Signal::SIGCONT,
++            "SIGSTOP" => Signal::SIGSTOP,
++            "SIGTSTP" => Signal::SIGTSTP,
++            "SIGTTIN" => Signal::SIGTTIN,
++            "SIGTTOU" => Signal::SIGTTOU,
++            "SIGURG" => Signal::SIGURG,
++            "SIGXCPU" => Signal::SIGXCPU,
++            "SIGXFSZ" => Signal::SIGXFSZ,
++            "SIGVTALRM" => Signal::SIGVTALRM,
++            "SIGPROF" => Signal::SIGPROF,
++            "SIGWINCH" => Signal::SIGWINCH,
++            "SIGIO" => Signal::SIGIO,
++            #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
++            "SIGPWR" => Signal::SIGPWR,
++            "SIGSYS" => Signal::SIGSYS,
++            #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
++            "SIGEMT" => Signal::SIGEMT,
++            #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
++            "SIGINFO" => Signal::SIGINFO,
++            _ => return Err(Error::invalid_argument()),
++        })
++    }
++}
++
++impl AsRef<str> for Signal {
++    fn as_ref(&self) -> &str {
++        match *self {
++            Signal::SIGHUP => "SIGHUP",
++            Signal::SIGINT => "SIGINT",
++            Signal::SIGQUIT => "SIGQUIT",
++            Signal::SIGILL => "SIGILL",
++            Signal::SIGTRAP => "SIGTRAP",
++            Signal::SIGABRT => "SIGABRT",
++            Signal::SIGBUS => "SIGBUS",
++            Signal::SIGFPE => "SIGFPE",
++            Signal::SIGKILL => "SIGKILL",
++            Signal::SIGUSR1 => "SIGUSR1",
++            Signal::SIGSEGV => "SIGSEGV",
++            Signal::SIGUSR2 => "SIGUSR2",
++            Signal::SIGPIPE => "SIGPIPE",
++            Signal::SIGALRM => "SIGALRM",
++            Signal::SIGTERM => "SIGTERM",
++            #[cfg(all(any(target_os = "android", target_os = "emscripten", target_os = "linux"),
++                      not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
++            Signal::SIGSTKFLT => "SIGSTKFLT",
++            Signal::SIGCHLD => "SIGCHLD",
++            Signal::SIGCONT => "SIGCONT",
++            Signal::SIGSTOP => "SIGSTOP",
++            Signal::SIGTSTP => "SIGTSTP",
++            Signal::SIGTTIN => "SIGTTIN",
++            Signal::SIGTTOU => "SIGTTOU",
++            Signal::SIGURG => "SIGURG",
++            Signal::SIGXCPU => "SIGXCPU",
++            Signal::SIGXFSZ => "SIGXFSZ",
++            Signal::SIGVTALRM => "SIGVTALRM",
++            Signal::SIGPROF => "SIGPROF",
++            Signal::SIGWINCH => "SIGWINCH",
++            Signal::SIGIO => "SIGIO",
++            #[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
++            Signal::SIGPWR => "SIGPWR",
++            Signal::SIGSYS => "SIGSYS",
++            #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
++            Signal::SIGEMT => "SIGEMT",
++            #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
++            Signal::SIGINFO => "SIGINFO",
++        }
++    }
++}
++
++impl fmt::Display for Signal {
++    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++        f.write_str(self.as_ref())
++    }
++}
++
++pub use self::Signal::*;
++
++#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
++const SIGNALS: [Signal; 31] = [
++    SIGHUP,
++    SIGINT,
++    SIGQUIT,
++    SIGILL,
++    SIGTRAP,
++    SIGABRT,
++    SIGBUS,
++    SIGFPE,
++    SIGKILL,
++    SIGUSR1,
++    SIGSEGV,
++    SIGUSR2,
++    SIGPIPE,
++    SIGALRM,
++    SIGTERM,
++    SIGSTKFLT,
++    SIGCHLD,
++    SIGCONT,
++    SIGSTOP,
++    SIGTSTP,
++    SIGTTIN,
++    SIGTTOU,
++    SIGURG,
++    SIGXCPU,
++    SIGXFSZ,
++    SIGVTALRM,
++    SIGPROF,
++    SIGWINCH,
++    SIGIO,
++    SIGPWR,
++    SIGSYS];
++#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64")))]
++const SIGNALS: [Signal; 30] = [
++    SIGHUP,
++    SIGINT,
++    SIGQUIT,
++    SIGILL,
++    SIGTRAP,
++    SIGABRT,
++    SIGBUS,
++    SIGFPE,
++    SIGKILL,
++    SIGUSR1,
++    SIGSEGV,
++    SIGUSR2,
++    SIGPIPE,
++    SIGALRM,
++    SIGTERM,
++    SIGCHLD,
++    SIGCONT,
++    SIGSTOP,
++    SIGTSTP,
++    SIGTTIN,
++    SIGTTOU,
++    SIGURG,
++    SIGXCPU,
++    SIGXFSZ,
++    SIGVTALRM,
++    SIGPROF,
++    SIGWINCH,
++    SIGIO,
++    SIGPWR,
++    SIGSYS];
++#[cfg(not(any(target_os = "linux", target_os = "android", target_os = "emscripten")))]
++const SIGNALS: [Signal; 31] = [
++    SIGHUP,
++    SIGINT,
++    SIGQUIT,
++    SIGILL,
++    SIGTRAP,
++    SIGABRT,
++    SIGBUS,
++    SIGFPE,
++    SIGKILL,
++    SIGUSR1,
++    SIGSEGV,
++    SIGUSR2,
++    SIGPIPE,
++    SIGALRM,
++    SIGTERM,
++    SIGCHLD,
++    SIGCONT,
++    SIGSTOP,
++    SIGTSTP,
++    SIGTTIN,
++    SIGTTOU,
++    SIGURG,
++    SIGXCPU,
++    SIGXFSZ,
++    SIGVTALRM,
++    SIGPROF,
++    SIGWINCH,
++    SIGIO,
++    SIGSYS,
++    SIGEMT,
++    SIGINFO];
++
++pub const NSIG: libc::c_int = 32;
++
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct SignalIterator {
++    next: usize,
++}
++
++impl Iterator for SignalIterator {
++    type Item = Signal;
++
++    fn next(&mut self) -> Option<Signal> {
++        if self.next < SIGNALS.len() {
++            let next_signal = SIGNALS[self.next];
++            self.next += 1;
++            Some(next_signal)
++        } else {
++            None
++        }
++    }
++}
++
++impl Signal {
++    pub fn iterator() -> SignalIterator {
++        SignalIterator{next: 0}
++    }
++
++    // We do not implement the From trait, because it is supposed to be infallible.
++    // With Rust RFC 1542 comes the appropriate trait TryFrom. Once it is
++    // implemented, we'll replace this function.
++    #[inline]
++    pub fn from_c_int(signum: libc::c_int) -> Result<Signal> {
++        if 0 < signum && signum < NSIG {
++            Ok(unsafe { mem::transmute(signum) })
++        } else {
++            Err(Error::invalid_argument())
++        }
++    }
++}
++
++pub const SIGIOT : Signal = SIGABRT;
++pub const SIGPOLL : Signal = SIGIO;
++pub const SIGUNUSED : Signal = SIGSYS;
++
++libc_bitflags!{
++    pub struct SaFlags: libc::c_int {
++        SA_NOCLDSTOP;
++        SA_NOCLDWAIT;
++        SA_NODEFER;
++        SA_ONSTACK;
++        SA_RESETHAND;
++        SA_RESTART;
++        SA_SIGINFO;
++    }
++}
++
++libc_enum! {
++    #[repr(i32)]
++    pub enum SigmaskHow {
++        SIG_BLOCK,
++        SIG_UNBLOCK,
++        SIG_SETMASK,
++    }
++}
++
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct SigSet {
++    sigset: libc::sigset_t
++}
++
++
++impl SigSet {
++    pub fn all() -> SigSet {
++        let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
++        let _ = unsafe { libc::sigfillset(&mut sigset as *mut libc::sigset_t) };
++
++        SigSet { sigset: sigset }
++    }
++
++    pub fn empty() -> SigSet {
++        let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
++        let _ = unsafe { libc::sigemptyset(&mut sigset as *mut libc::sigset_t) };
++
++        SigSet { sigset: sigset }
++    }
++
++    pub fn add(&mut self, signal: Signal) {
++        unsafe { libc::sigaddset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
++    }
++
++    pub fn clear(&mut self) {
++        unsafe { libc::sigemptyset(&mut self.sigset as *mut libc::sigset_t) };
++    }
++
++    pub fn remove(&mut self, signal: Signal) {
++        unsafe { libc::sigdelset(&mut self.sigset as *mut libc::sigset_t, signal as libc::c_int) };
++    }
++
++    pub fn contains(&self, signal: Signal) -> bool {
++        let res = unsafe { libc::sigismember(&self.sigset as *const libc::sigset_t, signal as libc::c_int) };
++
++        match res {
++            1 => true,
++            0 => false,
++            _ => unreachable!("unexpected value from sigismember"),
++        }
++    }
++
++    pub fn extend(&mut self, other: &SigSet) {
++        for signal in Signal::iterator() {
++            if other.contains(signal) {
++                self.add(signal);
++            }
++        }
++    }
++
++    /// Gets the currently blocked (masked) set of signals for the calling thread.
++    pub fn thread_get_mask() -> Result<SigSet> {
++        let mut oldmask: SigSet = unsafe { mem::uninitialized() };
++        pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(&mut oldmask))?;
++        Ok(oldmask)
++    }
++
++    /// Sets the set of signals as the signal mask for the calling thread.
++    pub fn thread_set_mask(&self) -> Result<()> {
++        pthread_sigmask(SigmaskHow::SIG_SETMASK, Some(self), None)
++    }
++
++    /// Adds the set of signals to the signal mask for the calling thread.
++    pub fn thread_block(&self) -> Result<()> {
++        pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(self), None)
++    }
++
++    /// Removes the set of signals from the signal mask for the calling thread.
++    pub fn thread_unblock(&self) -> Result<()> {
++        pthread_sigmask(SigmaskHow::SIG_UNBLOCK, Some(self), None)
++    }
++
++    /// Sets the set of signals as the signal mask, and returns the old mask.
++    pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> {
++        let mut oldmask: SigSet = unsafe { mem::uninitialized() };
++        pthread_sigmask(how, Some(self), Some(&mut oldmask))?;
++        Ok(oldmask)
++    }
++
++    /// Suspends execution of the calling thread until one of the signals in the
++    /// signal mask becomes pending, and returns the accepted signal.
++    pub fn wait(&self) -> Result<Signal> {
++        let mut signum: libc::c_int = unsafe { mem::uninitialized() };
++        let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, &mut signum) };
++
++        Errno::result(res).map(|_| Signal::from_c_int(signum).unwrap())
++    }
++}
++
++impl AsRef<libc::sigset_t> for SigSet {
++    fn as_ref(&self) -> &libc::sigset_t {
++        &self.sigset
++    }
++}
++
++/// A signal handler.
++#[allow(unknown_lints)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub enum SigHandler {
++    /// Default signal handling.
++    SigDfl,
++    /// Request that the signal be ignored.
++    SigIgn,
++    /// Use the given signal-catching function, which takes in the signal.
++    Handler(extern fn(libc::c_int)),
++    /// Use the given signal-catching function, which takes in the signal, information about how
++    /// the signal was generated, and a pointer to the threads `ucontext_t`.
++    SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
++}
++
++/// Action to take on receipt of a signal. Corresponds to `sigaction`.
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct SigAction {
++    sigaction: libc::sigaction
++}
++
++impl SigAction {
++    /// Creates a new action.
++    ///
++    /// The `SA_SIGINFO` bit in the `flags` argument is ignored (it will be set only if `handler`
++    /// is the `SigAction` variant). `mask` specifies other signals to block during execution of
++    /// the signal-catching function.
++    pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
++        let mut s = unsafe { mem::uninitialized::<libc::sigaction>() };
++        s.sa_sigaction = match handler {
++            SigHandler::SigDfl => libc::SIG_DFL,
++            SigHandler::SigIgn => libc::SIG_IGN,
++            SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
++            SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
++        };
++        s.sa_flags = match handler {
++            SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(),
++            _ => (flags - SaFlags::SA_SIGINFO).bits(),
++        };
++        s.sa_mask = mask.sigset;
++
++        SigAction { sigaction: s }
++    }
++
++    /// Returns the flags set on the action.
++    pub fn flags(&self) -> SaFlags {
++        SaFlags::from_bits_truncate(self.sigaction.sa_flags)
++    }
++
++    /// Returns the set of signals that are blocked during execution of the action's
++    /// signal-catching function.
++    pub fn mask(&self) -> SigSet {
++        SigSet { sigset: self.sigaction.sa_mask }
++    }
++
++    /// Returns the action's handler.
++    pub fn handler(&self) -> SigHandler {
++        match self.sigaction.sa_sigaction {
++            libc::SIG_DFL => SigHandler::SigDfl,
++            libc::SIG_IGN => SigHandler::SigIgn,
++            f if self.flags().contains(SaFlags::SA_SIGINFO) =>
++                SigHandler::SigAction( unsafe { mem::transmute(f) } ),
++            f => SigHandler::Handler( unsafe { mem::transmute(f) } ),
++        }
++    }
++}
++
++/// Changes the action taken by a process on receipt of a specific signal.
++///
++/// `signal` can be any signal except `SIGKILL` or `SIGSTOP`. On success, it returns the previous
++/// action for the given signal. If `sigaction` fails, no new signal handler is installed.
++///
++/// # Safety
++///
++/// Signal handlers may be called at any point during execution, which limits what is safe to do in
++/// the body of the signal-catching function. Be certain to only make syscalls that are explicitly
++/// marked safe for signal handlers and only share global data using atomics.
++pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> {
++    let mut oldact = mem::uninitialized::<libc::sigaction>();
++
++    let res =
++        libc::sigaction(signal as libc::c_int, &sigaction.sigaction as *const libc::sigaction, &mut oldact as *mut libc::sigaction);
++
++    Errno::result(res).map(|_| SigAction { sigaction: oldact })
++}
++
++/// Signal management (see [signal(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html))
++///
++/// Installs `handler` for the given `signal`, returning the previous signal
++/// handler. `signal` should only be used following another call to `signal` or
++/// if the current handler is the default. The return value of `signal` is
++/// undefined after setting the handler with [`sigaction`][SigActionFn].
++///
++/// # Safety
++///
++/// If the pointer to the previous signal handler is invalid, undefined
++/// behavior could be invoked when casting it back to a [`SigAction`][SigActionStruct].
++///
++/// # Examples
++///
++/// Ignore `SIGINT`:
++///
++/// ```no_run
++/// # use nix::sys::signal::{self, Signal, SigHandler};
++/// unsafe { signal::signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap();
++/// ```
++///
++/// Use a signal handler to set a flag variable:
++///
++/// ```no_run
++/// # #[macro_use] extern crate lazy_static;
++/// # extern crate libc;
++/// # extern crate nix;
++/// # use std::sync::atomic::{AtomicBool, Ordering};
++/// # use nix::sys::signal::{self, Signal, SigHandler};
++/// lazy_static! {
++///    static ref SIGNALED: AtomicBool = AtomicBool::new(false);
++/// }
++///
++/// extern fn handle_sigint(signal: libc::c_int) {
++///     let signal = Signal::from_c_int(signal).unwrap();
++///     SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed);
++/// }
++///
++/// fn main() {
++///     let handler = SigHandler::Handler(handle_sigint);
++///     unsafe { signal::signal(Signal::SIGINT, handler) }.unwrap();
++/// }
++/// ```
++///
++/// # Errors
++///
++/// Returns [`Error::UnsupportedOperation`] if `handler` is
++/// [`SigAction`][SigActionStruct]. Use [`sigaction`][SigActionFn] instead.
++///
++/// `signal` also returns any error from `libc::signal`, such as when an attempt
++/// is made to catch a signal that cannot be caught or to ignore a signal that
++/// cannot be ignored.
++///
++/// [`Error::UnsupportedOperation`]: ../../enum.Error.html#variant.UnsupportedOperation
++/// [SigActionStruct]: struct.SigAction.html
++/// [sigactionFn]: fn.sigaction.html
++pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler> {
++    let signal = signal as libc::c_int;
++    let res = match handler {
++        SigHandler::SigDfl => libc::signal(signal, libc::SIG_DFL),
++        SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN),
++        SigHandler::Handler(handler) => libc::signal(signal, handler as libc::sighandler_t),
++        SigHandler::SigAction(_) => return Err(Error::UnsupportedOperation),
++    };
++    Errno::result(res).map(|oldhandler| {
++        match oldhandler {
++            libc::SIG_DFL => SigHandler::SigDfl,
++            libc::SIG_IGN => SigHandler::SigIgn,
++            f => SigHandler::Handler(mem::transmute(f)),
++        }
++    })
++}
++
++/// Manages the signal mask (set of blocked signals) for the calling thread.
++///
++/// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
++/// The `how` flag decides the type of update. If `set` is `None`, `how` will be ignored,
++/// and no modification will take place.
++///
++/// If the 'oldset' parameter is `Some(..)` then the current signal mask will be written into it.
++///
++/// If both `set` and `oldset` is `Some(..)`, the current signal mask will be written into oldset,
++/// and then it will be updated with `set`.
++///
++/// If both `set` and `oldset` is None, this function is a no-op.
++///
++/// For more information, visit the [`pthread_sigmask`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_sigmask.html),
++/// or [`sigprocmask`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html) man pages.
++pub fn pthread_sigmask(how: SigmaskHow,
++                       set: Option<&SigSet>,
++                       oldset: Option<&mut SigSet>) -> Result<()> {
++    if set.is_none() && oldset.is_none() {
++        return Ok(())
++    }
++
++    let res = unsafe {
++        // if set or oldset is None, pass in null pointers instead
++        libc::pthread_sigmask(how as libc::c_int,
++                             set.map_or_else(ptr::null::<libc::sigset_t>,
++                                             |s| &s.sigset as *const libc::sigset_t),
++                             oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
++                                                |os| &mut os.sigset as *mut libc::sigset_t))
++    };
++
++    Errno::result(res).map(drop)
++}
++
++/// Examine and change blocked signals.
++///
++/// For more informations see the [`sigprocmask` man
++/// pages](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html).
++pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut SigSet>) -> Result<()> {
++    if set.is_none() && oldset.is_none() {
++        return Ok(())
++    }
++
++    let res = unsafe {
++        // if set or oldset is None, pass in null pointers instead
++        libc::sigprocmask(how as libc::c_int,
++                          set.map_or_else(ptr::null::<libc::sigset_t>,
++                                          |s| &s.sigset as *const libc::sigset_t),
++                          oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
++                                             |os| &mut os.sigset as *mut libc::sigset_t))
++    };
++
++    Errno::result(res).map(drop)
++}
++
++pub fn kill<T: Into<Option<Signal>>>(pid: ::unistd::Pid, signal: T) -> Result<()> {
++    let res = unsafe { libc::kill(pid.into(),
++                                  match signal.into() {
++                                      Some(s) => s as libc::c_int,
++                                      None => 0,
++                                  }) };
++
++    Errno::result(res).map(drop)
++}
++
++/// Send a signal to a process group [(see
++/// killpg(3))](http://pubs.opengroup.org/onlinepubs/9699919799/functions/killpg.html).
++///
++/// 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.
++pub fn killpg<T: Into<Option<Signal>>>(pgrp: ::unistd::Pid, signal: T) -> Result<()> {
++    let res = unsafe { libc::killpg(pgrp.into(),
++                                  match signal.into() {
++                                      Some(s) => s as libc::c_int,
++                                      None => 0,
++                                  }) };
++
++    Errno::result(res).map(drop)
++}
++
++pub fn raise(signal: Signal) -> Result<()> {
++    let res = unsafe { libc::raise(signal as libc::c_int) };
++
++    Errno::result(res).map(drop)
++}
++
++
++#[cfg(target_os = "freebsd")]
++pub type type_of_thread_id = libc::lwpid_t;
++#[cfg(target_os = "linux")]
++pub type type_of_thread_id = libc::pid_t;
++
++/// Used to request asynchronous notification of certain events, for example,
++/// with POSIX AIO, POSIX message queues, and POSIX timers.
++// sigval is actually a union of a int and a void*.  But it's never really used
++// as a pointer, because neither libc nor the kernel ever dereference it.  nix
++// therefore presents it as an intptr_t, which is how kevent uses it.
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub enum SigevNotify {
++    /// No notification will be delivered
++    SigevNone,
++    /// The signal given by `signal` will be delivered to the process.  The
++    /// value in `si_value` will be present in the `si_value` field of the
++    /// `siginfo_t` structure of the queued signal.
++    SigevSignal { signal: Signal, si_value: libc::intptr_t },
++    // Note: SIGEV_THREAD is not implemented because libc::sigevent does not
++    // expose a way to set the union members needed by SIGEV_THREAD.
++    /// A new `kevent` is posted to the kqueue `kq`.  The `kevent`'s `udata`
++    /// field will contain the value in `udata`.
++    #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++    SigevKevent { kq: RawFd, udata: libc::intptr_t },
++    /// The signal `signal` is queued to the thread whose LWP ID is given in
++    /// `thread_id`.  The value stored in `si_value` will be present in the
++    /// `si_value` of the `siginfo_t` structure of the queued signal.
++    #[cfg(any(target_os = "freebsd", target_os = "linux"))]
++    SigevThreadId { signal: Signal, thread_id: type_of_thread_id,
++                    si_value: libc::intptr_t },
++}
++
++#[cfg(not(target_os = "openbsd"))]
++mod sigevent {
++    use libc;
++    use std::mem;
++    use std::ptr;
++    use super::SigevNotify;
++    #[cfg(any(target_os = "freebsd", target_os = "linux"))]
++    use super::type_of_thread_id;
++
++    /// Used to request asynchronous notification of the completion of certain
++    /// events, such as POSIX AIO and timers.
++    #[repr(C)]
++    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++    pub struct SigEvent {
++        sigevent: libc::sigevent
++    }
++
++    impl SigEvent {
++        /// **Note:** this constructor does not allow the user to set the
++        /// `sigev_notify_kevent_flags` field.  That's considered ok because on FreeBSD
++        /// at least those flags don't do anything useful.  That field is part of a
++        /// union that shares space with the more genuinely useful fields.
++        ///
++        /// **Note:** This constructor also doesn't allow the caller to set the
++        /// `sigev_notify_function` or `sigev_notify_attributes` fields, which are
++        /// required for `SIGEV_THREAD`.  That's considered ok because on no operating
++        /// system is `SIGEV_THREAD` the most efficient way to deliver AIO
++        /// notification.  FreeBSD and DragonFly BSD programs should prefer `SIGEV_KEVENT`.
++        /// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or
++        /// `SIGEV_SIGNAL`.  That field is part of a union that shares space with the
++        /// more genuinely useful `sigev_notify_thread_id`
++        pub fn new(sigev_notify: SigevNotify) -> SigEvent {
++            let mut sev = unsafe { mem::zeroed::<libc::sigevent>()};
++            sev.sigev_notify = match sigev_notify {
++                SigevNotify::SigevNone => libc::SIGEV_NONE,
++                SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL,
++                #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++                SigevNotify::SigevKevent{..} => libc::SIGEV_KEVENT,
++                #[cfg(target_os = "freebsd")]
++                SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
++                #[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))]
++                SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID,
++                #[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))]
++                SigevNotify::SigevThreadId{..} => 4  // No SIGEV_THREAD_ID defined
++            };
++            sev.sigev_signo = match sigev_notify {
++                SigevNotify::SigevSignal{ signal, .. } => signal as libc::c_int,
++                #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++                SigevNotify::SigevKevent{ kq, ..} => kq,
++                #[cfg(any(target_os = "linux", target_os = "freebsd"))]
++                SigevNotify::SigevThreadId{ signal, .. } => signal as libc::c_int,
++                _ => 0
++            };
++            sev.sigev_value.sival_ptr = match sigev_notify {
++                SigevNotify::SigevNone => ptr::null_mut::<libc::c_void>(),
++                SigevNotify::SigevSignal{ si_value, .. } => si_value as *mut libc::c_void,
++                #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++                SigevNotify::SigevKevent{ udata, .. } => udata as *mut libc::c_void,
++                #[cfg(any(target_os = "freebsd", target_os = "linux"))]
++                SigevNotify::SigevThreadId{ si_value, .. } => si_value as *mut libc::c_void,
++            };
++            SigEvent::set_tid(&mut sev, &sigev_notify);
++            SigEvent{sigevent: sev}
++        }
++
++        #[cfg(any(target_os = "freebsd", target_os = "linux"))]
++        fn set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify) {
++            sev.sigev_notify_thread_id = match *sigev_notify {
++                SigevNotify::SigevThreadId { thread_id, .. } => thread_id,
++                _ => 0 as type_of_thread_id
++            };
++        }
++
++        #[cfg(not(any(target_os = "freebsd", target_os = "linux")))]
++        fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) {
++        }
++
++        pub fn sigevent(&self) -> libc::sigevent {
++            self.sigevent
++        }
++    }
++
++    impl<'a> From<&'a libc::sigevent> for SigEvent {
++        fn from(sigevent: &libc::sigevent) -> Self {
++            SigEvent{ sigevent: *sigevent }
++        }
++    }
++}
++
++#[cfg(test)]
++mod tests {
++    use std::thread;
++    use super::*;
++
++    #[test]
++    fn test_contains() {
++        let mut mask = SigSet::empty();
++        mask.add(SIGUSR1);
++
++        assert!(mask.contains(SIGUSR1));
++        assert!(!mask.contains(SIGUSR2));
++
++        let all = SigSet::all();
++        assert!(all.contains(SIGUSR1));
++        assert!(all.contains(SIGUSR2));
++    }
++
++    #[test]
++    fn test_clear() {
++        let mut set = SigSet::all();
++        set.clear();
++        for signal in Signal::iterator() {
++            assert!(!set.contains(signal));
++        }
++    }
++
++    #[test]
++    fn test_from_str_round_trips() {
++        for signal in Signal::iterator() {
++            assert_eq!(signal.as_ref().parse::<Signal>().unwrap(), signal);
++            assert_eq!(signal.to_string().parse::<Signal>().unwrap(), signal);
++        }
++    }
++
++    #[test]
++    fn test_from_str_invalid_value() {
++        let errval = Err(Error::Sys(Errno::EINVAL));
++        assert_eq!("NOSIGNAL".parse::<Signal>(), errval);
++        assert_eq!("kill".parse::<Signal>(), errval);
++        assert_eq!("9".parse::<Signal>(), errval);
++    }
++
++    #[test]
++    fn test_extend() {
++        let mut one_signal = SigSet::empty();
++        one_signal.add(SIGUSR1);
++
++        let mut two_signals = SigSet::empty();
++        two_signals.add(SIGUSR2);
++        two_signals.extend(&one_signal);
++
++        assert!(two_signals.contains(SIGUSR1));
++        assert!(two_signals.contains(SIGUSR2));
++    }
++
++    #[test]
++    fn test_thread_signal_set_mask() {
++        thread::spawn(|| {
++            let prev_mask = SigSet::thread_get_mask()
++                .expect("Failed to get existing signal mask!");
++
++            let mut test_mask = prev_mask;
++            test_mask.add(SIGUSR1);
++
++            assert!(test_mask.thread_set_mask().is_ok());
++            let new_mask = SigSet::thread_get_mask()
++                .expect("Failed to get new mask!");
++
++            assert!(new_mask.contains(SIGUSR1));
++            assert!(!new_mask.contains(SIGUSR2));
++
++            prev_mask.thread_set_mask().expect("Failed to revert signal mask!");
++        }).join().unwrap();
++    }
++
++    #[test]
++    fn test_thread_signal_block() {
++        thread::spawn(|| {
++            let mut mask = SigSet::empty();
++            mask.add(SIGUSR1);
++
++            assert!(mask.thread_block().is_ok());
++
++            assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
++        }).join().unwrap();
++    }
++
++    #[test]
++    fn test_thread_signal_unblock() {
++        thread::spawn(|| {
++            let mut mask = SigSet::empty();
++            mask.add(SIGUSR1);
++
++            assert!(mask.thread_unblock().is_ok());
++
++            assert!(!SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
++        }).join().unwrap();
++    }
++
++    #[test]
++    fn test_thread_signal_swap() {
++        thread::spawn(|| {
++            let mut mask = SigSet::empty();
++            mask.add(SIGUSR1);
++            mask.thread_block().unwrap();
++
++            assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR1));
++
++            let mut mask2 = SigSet::empty();
++            mask2.add(SIGUSR2);
++
++            let oldmask = mask2.thread_swap_mask(SigmaskHow::SIG_SETMASK)
++                .unwrap();
++
++            assert!(oldmask.contains(SIGUSR1));
++            assert!(!oldmask.contains(SIGUSR2));
++
++            assert!(SigSet::thread_get_mask().unwrap().contains(SIGUSR2));
++        }).join().unwrap();
++    }
++
++    #[test]
++    fn test_sigaction() {
++        use libc;
++        thread::spawn(|| {
++            extern fn test_sigaction_handler(_: libc::c_int) {}
++            extern fn test_sigaction_action(_: libc::c_int,
++                _: *mut libc::siginfo_t, _: *mut libc::c_void) {}
++
++            let handler_sig = SigHandler::Handler(test_sigaction_handler);
++
++            let flags = SaFlags::SA_ONSTACK | SaFlags::SA_RESTART |
++                        SaFlags::SA_SIGINFO;
++
++            let mut mask = SigSet::empty();
++            mask.add(SIGUSR1);
++
++            let action_sig = SigAction::new(handler_sig, flags, mask);
++
++            assert_eq!(action_sig.flags(),
++                       SaFlags::SA_ONSTACK | SaFlags::SA_RESTART);
++            assert_eq!(action_sig.handler(), handler_sig);
++
++            mask = action_sig.mask();
++            assert!(mask.contains(SIGUSR1));
++            assert!(!mask.contains(SIGUSR2));
++
++            let handler_act = SigHandler::SigAction(test_sigaction_action);
++            let action_act = SigAction::new(handler_act, flags, mask);
++            assert_eq!(action_act.handler(), handler_act);
++
++            let action_dfl = SigAction::new(SigHandler::SigDfl, flags, mask);
++            assert_eq!(action_dfl.handler(), SigHandler::SigDfl);
++
++            let action_ign = SigAction::new(SigHandler::SigIgn, flags, mask);
++            assert_eq!(action_ign.handler(), SigHandler::SigIgn);
++        }).join().unwrap();
++    }
++
++    #[test]
++    fn test_sigwait() {
++        thread::spawn(|| {
++            let mut mask = SigSet::empty();
++            mask.add(SIGUSR1);
++            mask.add(SIGUSR2);
++            mask.thread_block().unwrap();
++
++            raise(SIGUSR1).unwrap();
++            assert_eq!(mask.wait().unwrap(), SIGUSR1);
++        }).join().unwrap();
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/signalfd.rs b/third_party/rust/nix-0.15.0/src/sys/signalfd.rs
+new file mode 100644
+index 0000000000000..5425a27be9e52
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/signalfd.rs
+@@ -0,0 +1,170 @@
++//! Interface for the `signalfd` syscall.
++//!
++//! # Signal discarding
++//! When a signal can't be delivered to a process (or thread), it will become a pending signal.
++//! Failure to deliver could happen if the signal is blocked by every thread in the process or if
++//! the signal handler is still handling a previous signal.
++//!
++//! If a signal is sent to a process (or thread) that already has a pending signal of the same
++//! type, it will be discarded. This means that if signals of the same type are received faster than
++//! they are processed, some of those signals will be dropped. Because of this limitation,
++//! `signalfd` in itself cannot be used for reliable communication between processes or threads.
++//!
++//! Once the signal is unblocked, or the signal handler is finished, and a signal is still pending
++//! (ie. not consumed from a signalfd) it will be delivered to the signal handler.
++//!
++//! Please note that signal discarding is not specific to `signalfd`, but also happens with regular
++//! signal handlers.
++use libc;
++use unistd;
++use {Error, Result};
++use errno::Errno;
++pub use sys::signal::{self, SigSet};
++pub use libc::signalfd_siginfo as siginfo;
++
++use std::os::unix::io::{RawFd, AsRawFd};
++use std::mem;
++
++
++libc_bitflags!{
++    pub struct SfdFlags: libc::c_int {
++        SFD_NONBLOCK;
++        SFD_CLOEXEC;
++    }
++}
++
++pub const SIGNALFD_NEW: RawFd = -1;
++pub const SIGNALFD_SIGINFO_SIZE: usize = 128;
++
++/// Creates a new file descriptor for reading signals.
++///
++/// **Important:** please read the module level documentation about signal discarding before using
++/// this function!
++///
++/// The `mask` parameter specifies the set of signals that can be accepted via this file descriptor.
++///
++/// A signal must be blocked on every thread in a process, otherwise it won't be visible from
++/// signalfd (the default handler will be invoked instead).
++///
++/// See [the signalfd man page for more information](http://man7.org/linux/man-pages/man2/signalfd.2.html)
++pub fn signalfd(fd: RawFd, mask: &SigSet, flags: SfdFlags) -> Result<RawFd> {
++    unsafe {
++        Errno::result(libc::signalfd(fd as libc::c_int, mask.as_ref(), flags.bits()))
++    }
++}
++
++/// A helper struct for creating, reading and closing a `signalfd` instance.
++///
++/// **Important:** please read the module level documentation about signal discarding before using
++/// this struct!
++///
++/// # Examples
++///
++/// ```
++/// # use nix::sys::signalfd::*;
++/// // Set the thread to block the SIGUSR1 signal, otherwise the default handler will be used
++/// let mut mask = SigSet::empty();
++/// mask.add(signal::SIGUSR1);
++/// mask.thread_block().unwrap();
++///
++/// // Signals are queued up on the file descriptor
++/// let mut sfd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap();
++///
++/// match sfd.read_signal() {
++///     // we caught a signal
++///     Ok(Some(sig)) => (),
++///     // there were no signals waiting (only happens when the SFD_NONBLOCK flag is set,
++///     // otherwise the read_signal call blocks)
++///     Ok(None) => (),
++///     Err(err) => (), // some error happend
++/// }
++/// ```
++#[derive(Clone, Debug, Eq, Hash, PartialEq)]
++pub struct SignalFd(RawFd);
++
++impl SignalFd {
++    pub fn new(mask: &SigSet) -> Result<SignalFd> {
++        Self::with_flags(mask, SfdFlags::empty())
++    }
++
++    pub fn with_flags(mask: &SigSet, flags: SfdFlags) -> Result<SignalFd> {
++        let fd = signalfd(SIGNALFD_NEW, mask, flags)?;
++
++        Ok(SignalFd(fd))
++    }
++
++    pub fn set_mask(&mut self, mask: &SigSet) -> Result<()> {
++        signalfd(self.0, mask, SfdFlags::empty()).map(drop)
++    }
++
++    pub fn read_signal(&mut self) -> Result<Option<siginfo>> {
++        let mut buffer: [u8; SIGNALFD_SIGINFO_SIZE] = unsafe { mem::uninitialized() };
++
++        match unistd::read(self.0, &mut buffer) {
++            Ok(SIGNALFD_SIGINFO_SIZE) => Ok(Some(unsafe { mem::transmute(buffer) })),
++            Ok(_) => unreachable!("partial read on signalfd"),
++            Err(Error::Sys(Errno::EAGAIN)) => Ok(None),
++            Err(error) => Err(error)
++        }
++    }
++}
++
++impl Drop for SignalFd {
++    fn drop(&mut self) {
++        let _ = unistd::close(self.0);
++    }
++}
++
++impl AsRawFd for SignalFd {
++    fn as_raw_fd(&self) -> RawFd {
++        self.0
++    }
++}
++
++impl Iterator for SignalFd {
++    type Item = siginfo;
++
++    fn next(&mut self) -> Option<Self::Item> {
++        match self.read_signal() {
++            Ok(Some(sig)) => Some(sig),
++            Ok(None) | Err(_) => None,
++        }
++    }
++}
++
++
++#[cfg(test)]
++mod tests {
++    use super::*;
++    use std::mem;
++    use libc;
++
++
++    #[test]
++    fn check_siginfo_size() {
++        assert_eq!(mem::size_of::<libc::signalfd_siginfo>(), SIGNALFD_SIGINFO_SIZE);
++    }
++
++    #[test]
++    fn create_signalfd() {
++        let mask = SigSet::empty();
++        let fd = SignalFd::new(&mask);
++        assert!(fd.is_ok());
++    }
++
++    #[test]
++    fn create_signalfd_with_opts() {
++        let mask = SigSet::empty();
++        let fd = SignalFd::with_flags(&mask, SfdFlags::SFD_CLOEXEC | SfdFlags::SFD_NONBLOCK);
++        assert!(fd.is_ok());
++    }
++
++    #[test]
++    fn read_empty_signalfd() {
++        let mask = SigSet::empty();
++        let mut fd = SignalFd::with_flags(&mask, SfdFlags::SFD_NONBLOCK).unwrap();
++
++        let res = fd.read_signal();
++        assert!(res.unwrap().is_none());
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/socket/addr.rs b/third_party/rust/nix-0.15.0/src/sys/socket/addr.rs
+new file mode 100644
+index 0000000000000..ed41441155361
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/socket/addr.rs
+@@ -0,0 +1,1278 @@
++use super::sa_family_t;
++use {Error, Result, NixPath};
++use errno::Errno;
++use libc;
++use std::{fmt, mem, net, ptr, slice};
++use std::ffi::OsStr;
++use std::hash::{Hash, Hasher};
++use std::path::Path;
++use std::os::unix::ffi::OsStrExt;
++#[cfg(any(target_os = "android", target_os = "linux"))]
++use ::sys::socket::addr::netlink::NetlinkAddr;
++#[cfg(any(target_os = "android", target_os = "linux"))]
++use ::sys::socket::addr::alg::AlgAddr;
++#[cfg(any(target_os = "ios", target_os = "macos"))]
++use std::os::unix::io::RawFd;
++#[cfg(any(target_os = "ios", target_os = "macos"))]
++use ::sys::socket::addr::sys_control::SysControlAddr;
++#[cfg(any(target_os = "android",
++          target_os = "dragonfly",
++          target_os = "freebsd",
++          target_os = "ios",
++          target_os = "linux",
++          target_os = "macos",
++          target_os = "netbsd",
++          target_os = "openbsd"))]
++pub use self::datalink::LinkAddr;
++#[cfg(target_os = "linux")]
++pub use self::vsock::VsockAddr;
++
++/// These constants specify the protocol family to be used
++/// in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html)
++#[repr(i32)]
++#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
++pub enum AddressFamily {
++    /// Local communication (see [`unix(7)`](http://man7.org/linux/man-pages/man7/unix.7.html))
++    Unix = libc::AF_UNIX,
++    /// IPv4 Internet protocols (see [`ip(7)`](http://man7.org/linux/man-pages/man7/ip.7.html))
++    Inet = libc::AF_INET,
++    /// IPv6 Internet protocols (see [`ipv6(7)`](http://man7.org/linux/man-pages/man7/ipv6.7.html))
++    Inet6 = libc::AF_INET6,
++    /// Kernel user interface device (see [`netlink(7)`](http://man7.org/linux/man-pages/man7/netlink.7.html))
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Netlink = libc::AF_NETLINK,
++    /// Low level packet interface (see [`packet(7)`](http://man7.org/linux/man-pages/man7/packet.7.html))
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Packet = libc::AF_PACKET,
++    /// KEXT Controls and Notifications
++    #[cfg(any(target_os = "ios", target_os = "macos"))]
++    System = libc::AF_SYSTEM,
++    /// Amateur radio AX.25 protocol
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Ax25 = libc::AF_AX25,
++    /// IPX - Novell protocols
++    Ipx = libc::AF_IPX,
++    /// AppleTalk
++    AppleTalk = libc::AF_APPLETALK,
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    NetRom = libc::AF_NETROM,
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Bridge = libc::AF_BRIDGE,
++    /// Access to raw ATM PVCs
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    AtmPvc = libc::AF_ATMPVC,
++    /// ITU-T X.25 / ISO-8208 protocol (see [`x25(7)`](http://man7.org/linux/man-pages/man7/x25.7.html))
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    X25 = libc::AF_X25,
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Rose = libc::AF_ROSE,
++    Decnet = libc::AF_DECnet,
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    NetBeui = libc::AF_NETBEUI,
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Security = libc::AF_SECURITY,
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Key = libc::AF_KEY,
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Ash = libc::AF_ASH,
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Econet = libc::AF_ECONET,
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    AtmSvc = libc::AF_ATMSVC,
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Rds = libc::AF_RDS,
++    Sna = libc::AF_SNA,
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Irda = libc::AF_IRDA,
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Pppox = libc::AF_PPPOX,
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Wanpipe = libc::AF_WANPIPE,
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Llc = libc::AF_LLC,
++    #[cfg(target_os = "linux")]
++    Ib = libc::AF_IB,
++    #[cfg(target_os = "linux")]
++    Mpls = libc::AF_MPLS,
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Can = libc::AF_CAN,
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Tipc = libc::AF_TIPC,
++    #[cfg(not(any(target_os = "ios", target_os = "macos")))]
++    Bluetooth = libc::AF_BLUETOOTH,
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Iucv = libc::AF_IUCV,
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    RxRpc = libc::AF_RXRPC,
++    Isdn = libc::AF_ISDN,
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Phonet = libc::AF_PHONET,
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Ieee802154 = libc::AF_IEEE802154,
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Caif = libc::AF_CAIF,
++    /// Interface to kernel crypto API
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Alg = libc::AF_ALG,
++    #[cfg(target_os = "linux")]
++    Nfc = libc::AF_NFC,
++    #[cfg(target_os = "linux")]
++    Vsock = libc::AF_VSOCK,
++    #[cfg(any(target_os = "dragonfly",
++              target_os = "freebsd",
++              target_os = "ios",
++              target_os = "macos",
++              target_os = "netbsd",
++              target_os = "openbsd"))]
++    ImpLink = libc::AF_IMPLINK,
++    #[cfg(any(target_os = "dragonfly",
++              target_os = "freebsd",
++              target_os = "ios",
++              target_os = "macos",
++              target_os = "netbsd",
++              target_os = "openbsd"))]
++    Pup = libc::AF_PUP,
++    #[cfg(any(target_os = "dragonfly",
++              target_os = "freebsd",
++              target_os = "ios",
++              target_os = "macos",
++              target_os = "netbsd",
++              target_os = "openbsd"))]
++    Chaos = libc::AF_CHAOS,
++    #[cfg(any(target_os = "ios",
++              target_os = "macos",
++              target_os = "netbsd",
++              target_os = "openbsd"))]
++    Ns = libc::AF_NS,
++    #[cfg(any(target_os = "dragonfly",
++              target_os = "freebsd",
++              target_os = "ios",
++              target_os = "macos",
++              target_os = "netbsd",
++              target_os = "openbsd"))]
++    Iso = libc::AF_ISO,
++    #[cfg(any(target_os = "dragonfly",
++              target_os = "freebsd",
++              target_os = "ios",
++              target_os = "macos",
++              target_os = "netbsd",
++              target_os = "openbsd"))]
++    Datakit = libc::AF_DATAKIT,
++    #[cfg(any(target_os = "dragonfly",
++              target_os = "freebsd",
++              target_os = "ios",
++              target_os = "macos",
++              target_os = "netbsd",
++              target_os = "openbsd"))]
++    Ccitt = libc::AF_CCITT,
++    #[cfg(any(target_os = "dragonfly",
++              target_os = "freebsd",
++              target_os = "ios",
++              target_os = "macos",
++              target_os = "netbsd",
++              target_os = "openbsd"))]
++    Dli = libc::AF_DLI,
++    #[cfg(any(target_os = "dragonfly",
++              target_os = "freebsd",
++              target_os = "ios",
++              target_os = "macos",
++              target_os = "netbsd",
++              target_os = "openbsd"))]
++    Lat = libc::AF_LAT,
++    #[cfg(any(target_os = "dragonfly",
++              target_os = "freebsd",
++              target_os = "ios",
++              target_os = "macos",
++              target_os = "netbsd",
++              target_os = "openbsd"))]
++    Hylink = libc::AF_HYLINK,
++    #[cfg(any(target_os = "dragonfly",
++              target_os = "freebsd",
++              target_os = "ios",
++              target_os = "macos",
++              target_os = "netbsd",
++              target_os = "openbsd"))]
++    Link = libc::AF_LINK,
++    #[cfg(any(target_os = "dragonfly",
++              target_os = "freebsd",
++              target_os = "ios",
++              target_os = "macos",
++              target_os = "netbsd",
++              target_os = "openbsd"))]
++    Coip = libc::AF_COIP,
++    #[cfg(any(target_os = "dragonfly",
++              target_os = "freebsd",
++              target_os = "ios",
++              target_os = "macos",
++              target_os = "netbsd",
++              target_os = "openbsd"))]
++    Cnt = libc::AF_CNT,
++    #[cfg(any(target_os = "dragonfly",
++              target_os = "freebsd",
++              target_os = "ios",
++              target_os = "macos",
++              target_os = "netbsd",
++              target_os = "openbsd"))]
++    Natm = libc::AF_NATM,
++    /// Unspecified address family, (see [`getaddrinfo(3)`](http://man7.org/linux/man-pages/man3/getaddrinfo.3.html))
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Unspec = libc::AF_UNSPEC,
++}
++
++impl AddressFamily {
++    /// Create a new `AddressFamily` from an integer value retrieved from `libc`, usually from
++    /// the `sa_family` field of a `sockaddr`.
++    ///
++    /// Currently only supports these address families: Unix, Inet (v4 & v6), Netlink, Link/Packet
++    /// and System. Returns None for unsupported or unknown address families.
++    pub fn from_i32(family: i32) -> Option<AddressFamily> {
++        match family {
++            libc::AF_UNIX => Some(AddressFamily::Unix),
++            libc::AF_INET => Some(AddressFamily::Inet),
++            libc::AF_INET6 => Some(AddressFamily::Inet6),
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            libc::AF_NETLINK => Some(AddressFamily::Netlink),
++            #[cfg(any(target_os = "macos", target_os = "macos"))]
++            libc::AF_SYSTEM => Some(AddressFamily::System),
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            libc::AF_PACKET => Some(AddressFamily::Packet),
++            #[cfg(any(target_os = "dragonfly",
++                      target_os = "freebsd",
++                      target_os = "ios",
++                      target_os = "macos",
++                      target_os = "netbsd",
++                      target_os = "openbsd"))]
++            libc::AF_LINK => Some(AddressFamily::Link),
++            #[cfg(target_os = "linux")]
++            libc::AF_VSOCK => Some(AddressFamily::Vsock),
++            _ => None
++        }
++    }
++}
++
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub enum InetAddr {
++    V4(libc::sockaddr_in),
++    V6(libc::sockaddr_in6),
++}
++
++impl InetAddr {
++    pub fn from_std(std: &net::SocketAddr) -> InetAddr {
++        match *std {
++            net::SocketAddr::V4(ref addr) => {
++                InetAddr::V4(libc::sockaddr_in {
++                    sin_family: AddressFamily::Inet as sa_family_t,
++                    sin_port: addr.port().to_be(),  // network byte order
++                    sin_addr: Ipv4Addr::from_std(addr.ip()).0,
++                    .. unsafe { mem::zeroed() }
++                })
++            }
++            net::SocketAddr::V6(ref addr) => {
++                InetAddr::V6(libc::sockaddr_in6 {
++                    sin6_family: AddressFamily::Inet6 as sa_family_t,
++                    sin6_port: addr.port().to_be(),  // network byte order
++                    sin6_addr: Ipv6Addr::from_std(addr.ip()).0,
++                    sin6_flowinfo: addr.flowinfo(),  // host byte order
++                    sin6_scope_id: addr.scope_id(),  // host byte order
++                    .. unsafe { mem::zeroed() }
++                })
++            }
++        }
++    }
++
++    pub fn new(ip: IpAddr, port: u16) -> InetAddr {
++        match ip {
++            IpAddr::V4(ref ip) => {
++                InetAddr::V4(libc::sockaddr_in {
++                    sin_family: AddressFamily::Inet as sa_family_t,
++                    sin_port: port.to_be(),
++                    sin_addr: ip.0,
++                    .. unsafe { mem::zeroed() }
++                })
++            }
++            IpAddr::V6(ref ip) => {
++                InetAddr::V6(libc::sockaddr_in6 {
++                    sin6_family: AddressFamily::Inet6 as sa_family_t,
++                    sin6_port: port.to_be(),
++                    sin6_addr: ip.0,
++                    .. unsafe { mem::zeroed() }
++                })
++            }
++        }
++    }
++    /// Gets the IP address associated with this socket address.
++    pub fn ip(&self) -> IpAddr {
++        match *self {
++            InetAddr::V4(ref sa) => IpAddr::V4(Ipv4Addr(sa.sin_addr)),
++            InetAddr::V6(ref sa) => IpAddr::V6(Ipv6Addr(sa.sin6_addr)),
++        }
++    }
++
++    /// Gets the port number associated with this socket address
++    pub fn port(&self) -> u16 {
++        match *self {
++            InetAddr::V6(ref sa) => u16::from_be(sa.sin6_port),
++            InetAddr::V4(ref sa) => u16::from_be(sa.sin_port),
++        }
++    }
++
++    pub fn to_std(&self) -> net::SocketAddr {
++        match *self {
++            InetAddr::V4(ref sa) => net::SocketAddr::V4(
++                net::SocketAddrV4::new(
++                    Ipv4Addr(sa.sin_addr).to_std(),
++                    self.port())),
++            InetAddr::V6(ref sa) => net::SocketAddr::V6(
++                net::SocketAddrV6::new(
++                    Ipv6Addr(sa.sin6_addr).to_std(),
++                    self.port(),
++                    sa.sin6_flowinfo,
++                    sa.sin6_scope_id)),
++        }
++    }
++
++    pub fn to_str(&self) -> String {
++        format!("{}", self)
++    }
++}
++
++impl fmt::Display for InetAddr {
++    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++        match *self {
++            InetAddr::V4(_) => write!(f, "{}:{}", self.ip(), self.port()),
++            InetAddr::V6(_) => write!(f, "[{}]:{}", self.ip(), self.port()),
++        }
++    }
++}
++
++/*
++ *
++ * ===== IpAddr =====
++ *
++ */
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub enum IpAddr {
++    V4(Ipv4Addr),
++    V6(Ipv6Addr),
++}
++
++impl IpAddr {
++    /// Create a new IpAddr that contains an IPv4 address.
++    ///
++    /// The result will represent the IP address a.b.c.d
++    pub fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr {
++        IpAddr::V4(Ipv4Addr::new(a, b, c, d))
++    }
++
++    /// Create a new IpAddr that contains an IPv6 address.
++    ///
++    /// The result will represent the IP address a:b:c:d:e:f
++    pub fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> IpAddr {
++        IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h))
++    }
++
++    pub fn from_std(std: &net::IpAddr) -> IpAddr {
++        match *std {
++            net::IpAddr::V4(ref std) => IpAddr::V4(Ipv4Addr::from_std(std)),
++            net::IpAddr::V6(ref std) => IpAddr::V6(Ipv6Addr::from_std(std)),
++        }
++    }
++
++    pub fn to_std(&self) -> net::IpAddr {
++        match *self {
++            IpAddr::V4(ref ip) => net::IpAddr::V4(ip.to_std()),
++            IpAddr::V6(ref ip) => net::IpAddr::V6(ip.to_std()),
++        }
++    }
++}
++
++impl fmt::Display for IpAddr {
++    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++        match *self {
++            IpAddr::V4(ref v4) => v4.fmt(f),
++            IpAddr::V6(ref v6) => v6.fmt(f)
++        }
++    }
++}
++
++/*
++ *
++ * ===== Ipv4Addr =====
++ *
++ */
++
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct Ipv4Addr(pub libc::in_addr);
++
++impl Ipv4Addr {
++    pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
++        let ip = (((a as u32) << 24) |
++                  ((b as u32) << 16) |
++                  ((c as u32) <<  8) |
++                  ((d as u32) <<  0)).to_be();
++
++        Ipv4Addr(libc::in_addr { s_addr: ip })
++    }
++
++    pub fn from_std(std: &net::Ipv4Addr) -> Ipv4Addr {
++        let bits = std.octets();
++        Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
++    }
++
++    pub fn any() -> Ipv4Addr {
++        Ipv4Addr(libc::in_addr { s_addr: libc::INADDR_ANY })
++    }
++
++    pub fn octets(&self) -> [u8; 4] {
++        let bits = u32::from_be(self.0.s_addr);
++        [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8]
++    }
++
++    pub fn to_std(&self) -> net::Ipv4Addr {
++        let bits = self.octets();
++        net::Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
++    }
++}
++
++impl fmt::Display for Ipv4Addr {
++    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
++        let octets = self.octets();
++        write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
++    }
++}
++
++/*
++ *
++ * ===== Ipv6Addr =====
++ *
++ */
++
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct Ipv6Addr(pub libc::in6_addr);
++
++// Note that IPv6 addresses are stored in big endian order on all architectures.
++// See https://tools.ietf.org/html/rfc1700 or consult your favorite search
++// engine.
++
++macro_rules! to_u8_array {
++    ($($num:ident),*) => {
++        [ $(($num>>8) as u8, ($num&0xff) as u8,)* ]
++    }
++}
++
++macro_rules! to_u16_array {
++    ($slf:ident, $($first:expr, $second:expr),*) => {
++        [$( (($slf.0.s6_addr[$first] as u16) << 8) + $slf.0.s6_addr[$second] as u16,)*]
++    }
++}
++
++impl Ipv6Addr {
++    pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
++        let mut in6_addr_var: libc::in6_addr = unsafe{mem::uninitialized()};
++        in6_addr_var.s6_addr = to_u8_array!(a,b,c,d,e,f,g,h);
++        Ipv6Addr(in6_addr_var)
++    }
++
++    pub fn from_std(std: &net::Ipv6Addr) -> Ipv6Addr {
++        let s = std.segments();
++        Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7])
++    }
++
++    /// Return the eight 16-bit segments that make up this address
++    pub fn segments(&self) -> [u16; 8] {
++        to_u16_array!(self, 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)
++    }
++
++    pub fn to_std(&self) -> net::Ipv6Addr {
++        let s = self.segments();
++        net::Ipv6Addr::new(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7])
++    }
++}
++
++impl fmt::Display for Ipv6Addr {
++    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
++        self.to_std().fmt(fmt)
++    }
++}
++
++/// A wrapper around `sockaddr_un`.
++///
++/// This also tracks the length of `sun_path` address (excluding
++/// a terminating null), because it may not be null-terminated.  For example,
++/// unconnected and Linux abstract sockets are never null-terminated, and POSIX
++/// does not require that `sun_len` include the terminating null even for normal
++/// sockets.  Note that the actual sockaddr length is greater by
++/// `offset_of!(libc::sockaddr_un, sun_path)`
++#[derive(Clone, Copy, Debug)]
++pub struct UnixAddr(pub libc::sockaddr_un, pub usize);
++
++impl UnixAddr {
++    /// Create a new sockaddr_un representing a filesystem path.
++    pub fn new<P: ?Sized + NixPath>(path: &P) -> Result<UnixAddr> {
++        path.with_nix_path(|cstr| {
++            unsafe {
++                let mut ret = libc::sockaddr_un {
++                    sun_family: AddressFamily::Unix as sa_family_t,
++                    .. mem::zeroed()
++                };
++
++                let bytes = cstr.to_bytes();
++
++                if bytes.len() > ret.sun_path.len() {
++                    return Err(Error::Sys(Errno::ENAMETOOLONG));
++                }
++
++                ptr::copy_nonoverlapping(bytes.as_ptr(),
++                                         ret.sun_path.as_mut_ptr() as *mut u8,
++                                         bytes.len());
++
++                Ok(UnixAddr(ret, bytes.len()))
++            }
++        })?
++    }
++
++    /// Create a new `sockaddr_un` representing an address in the "abstract namespace".
++    ///
++    /// The leading null byte for the abstract namespace is automatically added;
++    /// thus the input `path` is expected to be the bare name, not null-prefixed.
++    /// This is a Linux-specific extension, primarily used to allow chrooted
++    /// processes to communicate with processes having a different filesystem view.
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    pub fn new_abstract(path: &[u8]) -> Result<UnixAddr> {
++        unsafe {
++            let mut ret = libc::sockaddr_un {
++                sun_family: AddressFamily::Unix as sa_family_t,
++                .. mem::zeroed()
++            };
++
++            if path.len() + 1 > ret.sun_path.len() {
++                return Err(Error::Sys(Errno::ENAMETOOLONG));
++            }
++
++            // Abstract addresses are represented by sun_path[0] ==
++            // b'\0', so copy starting one byte in.
++            ptr::copy_nonoverlapping(path.as_ptr(),
++                                     ret.sun_path.as_mut_ptr().offset(1) as *mut u8,
++                                     path.len());
++
++            Ok(UnixAddr(ret, ret.sun_path.len()))
++        }
++    }
++
++    fn sun_path(&self) -> &[u8] {
++        unsafe { slice::from_raw_parts(self.0.sun_path.as_ptr() as *const u8, self.1) }
++    }
++
++    /// If this address represents a filesystem path, return that path.
++    pub fn path(&self) -> Option<&Path> {
++        if self.1 == 0 || self.0.sun_path[0] == 0 {
++            // unnamed or abstract
++            None
++        } else {
++            let p = self.sun_path();
++            // POSIX only requires that `sun_len` be at least long enough to
++            // contain the pathname, and it need not be null-terminated.  So we
++            // need to create a string that is the shorter of the
++            // null-terminated length or the full length.
++            let ptr = &self.0.sun_path as *const libc::c_char;
++            let reallen = unsafe { libc::strnlen(ptr, p.len()) };
++            Some(Path::new(<OsStr as OsStrExt>::from_bytes(&p[..reallen])))
++        }
++    }
++
++    /// If this address represents an abstract socket, return its name.
++    ///
++    /// For abstract sockets only the bare name is returned, without the
++    /// leading null byte. `None` is returned for unnamed or path-backed sockets.
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    pub fn as_abstract(&self) -> Option<&[u8]> {
++        if self.1 >= 1 && self.0.sun_path[0] == 0 {
++            Some(&self.sun_path()[1..])
++        } else {
++            // unnamed or filesystem path
++            None
++        }
++    }
++}
++
++impl fmt::Display for UnixAddr {
++    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++        if self.1 == 0 {
++            f.write_str("<unbound UNIX socket>")
++        } else if let Some(path) = self.path() {
++            path.display().fmt(f)
++        } else {
++            let display = String::from_utf8_lossy(&self.sun_path()[1..]);
++            write!(f, "@{}", display)
++        }
++    }
++}
++
++impl PartialEq for UnixAddr {
++    fn eq(&self, other: &UnixAddr) -> bool {
++        self.sun_path() == other.sun_path()
++    }
++}
++
++impl Eq for UnixAddr {}
++
++impl Hash for UnixAddr {
++    fn hash<H: Hasher>(&self, s: &mut H) {
++        ( self.0.sun_family, self.sun_path() ).hash(s)
++    }
++}
++
++/// Represents a socket address
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub enum SockAddr {
++    Inet(InetAddr),
++    Unix(UnixAddr),
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Netlink(NetlinkAddr),
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Alg(AlgAddr),
++    #[cfg(any(target_os = "ios", target_os = "macos"))]
++    SysControl(SysControlAddr),
++    /// Datalink address (MAC)
++    #[cfg(any(target_os = "android",
++              target_os = "dragonfly",
++              target_os = "freebsd",
++              target_os = "ios",
++              target_os = "linux",
++              target_os = "macos",
++              target_os = "netbsd",
++              target_os = "openbsd"))]
++    Link(LinkAddr),
++    #[cfg(target_os = "linux")]
++    Vsock(VsockAddr),
++}
++
++impl SockAddr {
++    pub fn new_inet(addr: InetAddr) -> SockAddr {
++        SockAddr::Inet(addr)
++    }
++
++    pub fn new_unix<P: ?Sized + NixPath>(path: &P) -> Result<SockAddr> {
++        Ok(SockAddr::Unix(UnixAddr::new(path)?))
++    }
++
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    pub fn new_netlink(pid: u32, groups: u32) -> SockAddr {
++        SockAddr::Netlink(NetlinkAddr::new(pid, groups))
++    }
++
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    pub fn new_alg(alg_type: &str, alg_name: &str) -> SockAddr {
++        SockAddr::Alg(AlgAddr::new(alg_type, alg_name))
++    }
++
++    #[cfg(any(target_os = "ios", target_os = "macos"))]
++    pub fn new_sys_control(sockfd: RawFd, name: &str, unit: u32) -> Result<SockAddr> {
++        SysControlAddr::from_name(sockfd, name, unit).map(|a| SockAddr::SysControl(a))
++    }
++
++    #[cfg(target_os = "linux")]
++    pub fn new_vsock(cid: u32, port: u32) -> SockAddr {
++        SockAddr::Vsock(VsockAddr::new(cid, port))
++    }
++
++    pub fn family(&self) -> AddressFamily {
++        match *self {
++            SockAddr::Inet(InetAddr::V4(..)) => AddressFamily::Inet,
++            SockAddr::Inet(InetAddr::V6(..)) => AddressFamily::Inet6,
++            SockAddr::Unix(..) => AddressFamily::Unix,
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            SockAddr::Netlink(..) => AddressFamily::Netlink,
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            SockAddr::Alg(..) => AddressFamily::Alg,
++            #[cfg(any(target_os = "ios", target_os = "macos"))]
++            SockAddr::SysControl(..) => AddressFamily::System,
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            SockAddr::Link(..) => AddressFamily::Packet,
++            #[cfg(any(target_os = "dragonfly",
++                      target_os = "freebsd",
++                      target_os = "ios",
++                      target_os = "macos",
++                      target_os = "netbsd",
++                      target_os = "openbsd"))]
++            SockAddr::Link(..) => AddressFamily::Link,
++            #[cfg(target_os = "linux")]
++            SockAddr::Vsock(..) => AddressFamily::Vsock,
++        }
++    }
++
++    pub fn to_str(&self) -> String {
++        format!("{}", self)
++    }
++
++    /// Creates a `SockAddr` struct from libc's sockaddr.
++    ///
++    /// Supports only the following address families: Unix, Inet (v4 & v6), Netlink and System.
++    /// Returns None for unsupported families.
++    pub unsafe fn from_libc_sockaddr(addr: *const libc::sockaddr) -> Option<SockAddr> {
++        if addr.is_null() {
++            None
++        } else {
++            match AddressFamily::from_i32((*addr).sa_family as i32) {
++                Some(AddressFamily::Unix) => None,
++                Some(AddressFamily::Inet) => Some(SockAddr::Inet(
++                    InetAddr::V4(*(addr as *const libc::sockaddr_in)))),
++                Some(AddressFamily::Inet6) => Some(SockAddr::Inet(
++                    InetAddr::V6(*(addr as *const libc::sockaddr_in6)))),
++                #[cfg(any(target_os = "android", target_os = "linux"))]
++                Some(AddressFamily::Netlink) => Some(SockAddr::Netlink(
++                    NetlinkAddr(*(addr as *const libc::sockaddr_nl)))),
++                #[cfg(any(target_os = "ios", target_os = "macos"))]
++                Some(AddressFamily::System) => Some(SockAddr::SysControl(
++                    SysControlAddr(*(addr as *const libc::sockaddr_ctl)))),
++                #[cfg(any(target_os = "android", target_os = "linux"))]
++                Some(AddressFamily::Packet) => Some(SockAddr::Link(
++                    LinkAddr(*(addr as *const libc::sockaddr_ll)))),
++                #[cfg(any(target_os = "dragonfly",
++                          target_os = "freebsd",
++                          target_os = "ios",
++                          target_os = "macos",
++                          target_os = "netbsd",
++                          target_os = "openbsd"))]
++                Some(AddressFamily::Link) => {
++                    let ether_addr = LinkAddr(*(addr as *const libc::sockaddr_dl));
++                    if ether_addr.is_empty() {
++                        None
++                    } else {
++                        Some(SockAddr::Link(ether_addr))
++                    }
++                },
++                #[cfg(target_os = "linux")]
++                Some(AddressFamily::Vsock) => Some(SockAddr::Vsock(
++                    VsockAddr(*(addr as *const libc::sockaddr_vm)))),
++                // Other address families are currently not supported and simply yield a None
++                // entry instead of a proper conversion to a `SockAddr`.
++                Some(_) | None => None,
++            }
++        }
++    }
++
++    /// Conversion from nix's SockAddr type to the underlying libc sockaddr type.
++    ///
++    /// This is useful for interfacing with other libc functions that don't yet have nix wrappers.
++    /// Returns a reference to the underlying data type (as a sockaddr reference) along
++    /// with the size of the actual data type. sockaddr is commonly used as a proxy for
++    /// a superclass as C doesn't support inheritance, so many functions that take
++    /// a sockaddr * need to take the size of the underlying type as well and then internally cast it back.
++    pub unsafe fn as_ffi_pair(&self) -> (&libc::sockaddr, libc::socklen_t) {
++        match *self {
++            SockAddr::Inet(InetAddr::V4(ref addr)) => (mem::transmute(addr), mem::size_of::<libc::sockaddr_in>() as libc::socklen_t),
++            SockAddr::Inet(InetAddr::V6(ref addr)) => (mem::transmute(addr), mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t),
++            SockAddr::Unix(UnixAddr(ref addr, len)) => (mem::transmute(addr), (len + offset_of!(libc::sockaddr_un, sun_path)) as libc::socklen_t),
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            SockAddr::Netlink(NetlinkAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t),
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            SockAddr::Alg(AlgAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_alg>() as libc::socklen_t),
++            #[cfg(any(target_os = "ios", target_os = "macos"))]
++            SockAddr::SysControl(SysControlAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_ctl>() as libc::socklen_t),
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            SockAddr::Link(LinkAddr(ref ether_addr)) => (mem::transmute(ether_addr), mem::size_of::<libc::sockaddr_ll>() as libc::socklen_t),
++            #[cfg(any(target_os = "dragonfly",
++                      target_os = "freebsd",
++                      target_os = "ios",
++                      target_os = "macos",
++                      target_os = "netbsd",
++                      target_os = "openbsd"))]
++            SockAddr::Link(LinkAddr(ref ether_addr)) => (mem::transmute(ether_addr), mem::size_of::<libc::sockaddr_dl>() as libc::socklen_t),
++            #[cfg(target_os = "linux")]
++            SockAddr::Vsock(VsockAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_vm>() as libc::socklen_t),
++        }
++    }
++}
++
++impl fmt::Display for SockAddr {
++    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++        match *self {
++            SockAddr::Inet(ref inet) => inet.fmt(f),
++            SockAddr::Unix(ref unix) => unix.fmt(f),
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            SockAddr::Netlink(ref nl) => nl.fmt(f),
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            SockAddr::Alg(ref nl) => nl.fmt(f),
++            #[cfg(any(target_os = "ios", target_os = "macos"))]
++            SockAddr::SysControl(ref sc) => sc.fmt(f),
++            #[cfg(any(target_os = "android",
++                      target_os = "dragonfly",
++                      target_os = "freebsd",
++                      target_os = "ios",
++                      target_os = "linux",
++                      target_os = "macos",
++                      target_os = "netbsd",
++                      target_os = "openbsd"))]
++            SockAddr::Link(ref ether_addr) => ether_addr.fmt(f),
++            #[cfg(target_os = "linux")]
++            SockAddr::Vsock(ref svm) => svm.fmt(f),
++        }
++    }
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub mod netlink {
++    use ::sys::socket::addr::AddressFamily;
++    use libc::{sa_family_t, sockaddr_nl};
++    use std::{fmt, mem};
++
++    #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
++    pub struct NetlinkAddr(pub sockaddr_nl);
++
++    impl NetlinkAddr {
++        pub fn new(pid: u32, groups: u32) -> NetlinkAddr {
++            let mut addr: sockaddr_nl = unsafe { mem::zeroed() };
++            addr.nl_family = AddressFamily::Netlink as sa_family_t;
++            addr.nl_pid = pid;
++            addr.nl_groups = groups;
++
++            NetlinkAddr(addr)
++        }
++
++        pub fn pid(&self) -> u32 {
++            self.0.nl_pid
++        }
++
++        pub fn groups(&self) -> u32 {
++            self.0.nl_groups
++        }
++    }
++
++    impl fmt::Display for NetlinkAddr {
++        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++            write!(f, "pid: {} groups: {}", self.pid(), self.groups())
++        }
++    }
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub mod alg {
++    use libc::{AF_ALG, sockaddr_alg, c_char};
++    use std::{fmt, mem, str};
++    use std::hash::{Hash, Hasher};
++    use std::ffi::CStr;
++
++    #[derive(Copy, Clone)]
++    pub struct AlgAddr(pub sockaddr_alg);
++
++    // , PartialEq, Eq, Debug, Hash
++    impl PartialEq for AlgAddr {
++        fn eq(&self, other: &Self) -> bool {
++            let (inner, other) = (self.0, other.0);
++            (inner.salg_family, &inner.salg_type[..], inner.salg_feat, inner.salg_mask, &inner.salg_name[..]) ==
++            (other.salg_family, &other.salg_type[..], other.salg_feat, other.salg_mask, &other.salg_name[..])
++        }
++    }
++
++    impl Eq for AlgAddr {}
++
++    impl Hash for AlgAddr {
++        fn hash<H: Hasher>(&self, s: &mut H) {
++            let inner = self.0;
++            (inner.salg_family, &inner.salg_type[..], inner.salg_feat, inner.salg_mask, &inner.salg_name[..]).hash(s);
++        }
++    }
++
++    impl AlgAddr {
++        pub fn new(alg_type: &str, alg_name: &str) -> AlgAddr {
++            let mut addr: sockaddr_alg = unsafe { mem::zeroed() };
++            addr.salg_family = AF_ALG as u16;
++            addr.salg_type[..alg_type.len()].copy_from_slice(alg_type.to_string().as_bytes());
++            addr.salg_name[..alg_name.len()].copy_from_slice(alg_name.to_string().as_bytes());
++
++            AlgAddr(addr)
++        }
++
++
++        pub fn alg_type(&self) -> &CStr {
++            unsafe { CStr::from_ptr(self.0.salg_type.as_ptr() as *const c_char) }
++        }
++
++        pub fn alg_name(&self) -> &CStr {
++            unsafe { CStr::from_ptr(self.0.salg_name.as_ptr() as *const c_char) }
++        }
++    }
++
++    impl fmt::Display for AlgAddr {
++        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++            write!(f, "type: {} alg: {}",
++                   self.alg_name().to_string_lossy(),
++                   self.alg_type().to_string_lossy())
++        }
++    }
++
++    impl fmt::Debug for AlgAddr {
++        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++            fmt::Display::fmt(self, f)
++        }
++    }
++}
++
++#[cfg(any(target_os = "ios", target_os = "macos"))]
++pub mod sys_control {
++    use ::sys::socket::addr::AddressFamily;
++    use libc::{self, c_uchar};
++    use std::{fmt, mem};
++    use std::os::unix::io::RawFd;
++    use {Errno, Error, Result};
++
++    // FIXME: Move type into `libc`
++    #[repr(C)]
++    #[derive(Clone, Copy)]
++    #[allow(missing_debug_implementations)]
++    pub struct ctl_ioc_info {
++        pub ctl_id: u32,
++        pub ctl_name: [c_uchar; MAX_KCTL_NAME],
++    }
++
++    const CTL_IOC_MAGIC: u8 = 'N' as u8;
++    const CTL_IOC_INFO: u8 = 3;
++    const MAX_KCTL_NAME: usize = 96;
++
++    ioctl_readwrite!(ctl_info, CTL_IOC_MAGIC, CTL_IOC_INFO, ctl_ioc_info);
++
++    #[repr(C)]
++    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++    pub struct SysControlAddr(pub libc::sockaddr_ctl);
++
++    impl SysControlAddr {
++        pub fn new(id: u32, unit: u32) -> SysControlAddr {
++            let addr = libc::sockaddr_ctl {
++                sc_len: mem::size_of::<libc::sockaddr_ctl>() as c_uchar,
++                sc_family: AddressFamily::System as c_uchar,
++                ss_sysaddr: libc::AF_SYS_CONTROL as u16,
++                sc_id: id,
++                sc_unit: unit,
++                sc_reserved: [0; 5]
++            };
++
++            SysControlAddr(addr)
++        }
++
++        pub fn from_name(sockfd: RawFd, name: &str, unit: u32) -> Result<SysControlAddr> {
++            if name.len() > MAX_KCTL_NAME {
++                return Err(Error::Sys(Errno::ENAMETOOLONG));
++            }
++
++            let mut ctl_name = [0; MAX_KCTL_NAME];
++            ctl_name[..name.len()].clone_from_slice(name.as_bytes());
++            let mut info = ctl_ioc_info { ctl_id: 0, ctl_name: ctl_name };
++
++            unsafe { ctl_info(sockfd, &mut info)?; }
++
++            Ok(SysControlAddr::new(info.ctl_id, unit))
++        }
++
++        pub fn id(&self) -> u32 {
++            self.0.sc_id
++        }
++
++        pub fn unit(&self) -> u32 {
++            self.0.sc_unit
++        }
++    }
++
++    impl fmt::Display for SysControlAddr {
++        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++            fmt::Debug::fmt(self, f)
++        }
++    }
++}
++
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++mod datalink {
++    use super::{libc, fmt, AddressFamily};
++
++    /// Hardware Address
++    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++    pub struct LinkAddr(pub libc::sockaddr_ll);
++
++    impl LinkAddr {
++        /// Always AF_PACKET
++        pub fn family(&self) -> AddressFamily {
++            assert_eq!(self.0.sll_family as i32, libc::AF_PACKET);
++            AddressFamily::Packet
++        }
++
++        /// Physical-layer protocol
++        pub fn protocol(&self) -> u16 {
++            self.0.sll_protocol
++        }
++
++        /// Interface number
++        pub fn ifindex(&self) -> usize {
++            self.0.sll_ifindex as usize
++        }
++
++        /// ARP hardware type
++        pub fn hatype(&self) -> u16 {
++            self.0.sll_hatype
++        }
++
++        /// Packet type
++        pub fn pkttype(&self) -> u8 {
++            self.0.sll_pkttype
++        }
++
++        /// Length of MAC address
++        pub fn halen(&self) -> usize {
++            self.0.sll_halen as usize
++        }
++
++        /// Physical-layer address (MAC)
++        pub fn addr(&self) -> [u8; 6] {
++            let a = self.0.sll_addr[0] as u8;
++            let b = self.0.sll_addr[1] as u8;
++            let c = self.0.sll_addr[2] as u8;
++            let d = self.0.sll_addr[3] as u8;
++            let e = self.0.sll_addr[4] as u8;
++            let f = self.0.sll_addr[5] as u8;
++
++            [a, b, c, d, e, f]
++        }
++    }
++
++    impl fmt::Display for LinkAddr {
++        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++            let addr = self.addr();
++            write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
++                addr[0],
++                addr[1],
++                addr[2],
++                addr[3],
++                addr[4],
++                addr[5])
++        }
++    }
++}
++
++#[cfg(any(target_os = "dragonfly",
++          target_os = "freebsd",
++          target_os = "ios",
++          target_os = "macos",
++          target_os = "netbsd",
++          target_os = "openbsd"))]
++mod datalink {
++    use super::{libc, fmt, AddressFamily};
++
++    /// Hardware Address
++    #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++    pub struct LinkAddr(pub libc::sockaddr_dl);
++
++    impl LinkAddr {
++        /// Total length of sockaddr
++        pub fn len(&self) -> usize {
++            self.0.sdl_len as usize
++        }
++
++        /// always == AF_LINK
++        pub fn family(&self) -> AddressFamily {
++            assert_eq!(self.0.sdl_family as i32, libc::AF_LINK);
++            AddressFamily::Link
++        }
++
++        /// interface index, if != 0, system given index for interface
++        pub fn ifindex(&self) -> usize {
++            self.0.sdl_index as usize
++        }
++
++        /// Datalink type
++        pub fn datalink_type(&self) -> u8 {
++            self.0.sdl_type
++        }
++
++        // MAC address start position
++        pub fn nlen(&self) -> usize {
++            self.0.sdl_nlen as usize
++        }
++
++        /// link level address length
++        pub fn alen(&self) -> usize {
++            self.0.sdl_alen as usize
++        }
++
++        /// link layer selector length
++        pub fn slen(&self) -> usize {
++            self.0.sdl_slen as usize
++        }
++
++        /// if link level address length == 0,
++        /// or `sdl_data` not be larger.
++        pub fn is_empty(&self) -> bool {
++            let nlen = self.nlen();
++            let alen = self.alen();
++            let data_len = self.0.sdl_data.len();
++
++            if alen > 0 && nlen + alen < data_len {
++                false
++            } else {
++                true
++            }
++        }
++
++        /// Physical-layer address (MAC)
++        pub fn addr(&self) -> [u8; 6] {
++            let nlen = self.nlen();
++            let data = self.0.sdl_data;
++
++            assert!(!self.is_empty());
++
++            let a = data[nlen] as u8;
++            let b = data[nlen + 1] as u8;
++            let c = data[nlen + 2] as u8;
++            let d = data[nlen + 3] as u8;
++            let e = data[nlen + 4] as u8;
++            let f = data[nlen + 5] as u8;
++
++            [a, b, c, d, e, f]
++        }
++    }
++
++    impl fmt::Display for LinkAddr {
++        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++            let addr = self.addr();
++            write!(f, "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
++                addr[0],
++                addr[1],
++                addr[2],
++                addr[3],
++                addr[4],
++                addr[5])
++        }
++    }
++}
++
++#[cfg(target_os = "linux")]
++pub mod vsock {
++    use ::sys::socket::addr::AddressFamily;
++    use libc::{sa_family_t, sockaddr_vm};
++    use std::{fmt, mem};
++    use std::hash::{Hash, Hasher};
++
++    #[derive(Copy, Clone)]
++    pub struct VsockAddr(pub sockaddr_vm);
++
++    impl PartialEq for VsockAddr {
++        fn eq(&self, other: &Self) -> bool {
++            let (inner, other) = (self.0, other.0);
++            (inner.svm_family, inner.svm_cid, inner.svm_port) ==
++            (other.svm_family, other.svm_cid, other.svm_port)
++        }
++    }
++
++    impl Eq for VsockAddr {}
++
++    impl Hash for VsockAddr {
++        fn hash<H: Hasher>(&self, s: &mut H) {
++            let inner = self.0;
++            (inner.svm_family, inner.svm_cid, inner.svm_port).hash(s);
++        }
++    }
++
++    /// VSOCK Address
++    ///
++    /// The address for AF_VSOCK socket is defined as a combination of a
++    /// 32-bit Context Identifier (CID) and a 32-bit port number.
++    impl VsockAddr {
++        pub fn new(cid: u32, port: u32) -> VsockAddr {
++            let mut addr: sockaddr_vm = unsafe { mem::zeroed() };
++            addr.svm_family = AddressFamily::Vsock as sa_family_t;
++            addr.svm_cid = cid;
++            addr.svm_port = port;
++
++            VsockAddr(addr)
++        }
++
++        /// Context Identifier (CID)
++        pub fn cid(&self) -> u32 {
++            self.0.svm_cid
++        }
++
++        /// Port number
++        pub fn port(&self) -> u32 {
++            self.0.svm_port
++        }
++    }
++
++    impl fmt::Display for VsockAddr {
++        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++            write!(f, "cid: {} port: {}", self.cid(), self.port())
++        }
++    }
++
++    impl fmt::Debug for VsockAddr {
++        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++            fmt::Display::fmt(self, f)
++        }
++    }
++}
++
++#[cfg(test)]
++mod tests {
++    #[cfg(any(target_os = "android",
++              target_os = "dragonfly",
++              target_os = "freebsd",
++              target_os = "ios",
++              target_os = "linux",
++              target_os = "macos",
++              target_os = "netbsd",
++              target_os = "openbsd"))]
++    use super::*;
++
++    #[cfg(any(target_os = "dragonfly",
++              target_os = "freebsd",
++              target_os = "ios",
++              target_os = "macos",
++              target_os = "netbsd",
++              target_os = "openbsd"))]
++    #[test]
++    fn test_macos_loopback_datalink_addr() {
++        let bytes = [20i8, 18, 1, 0, 24, 3, 0, 0, 108, 111, 48, 0, 0, 0, 0, 0];
++        let sa = bytes.as_ptr() as *const libc::sockaddr;
++        let _sock_addr = unsafe { SockAddr::from_libc_sockaddr(sa) };
++        assert!(_sock_addr.is_none());
++    }
++
++    #[cfg(any(target_os = "dragonfly",
++              target_os = "freebsd",
++              target_os = "ios",
++              target_os = "macos",
++              target_os = "netbsd",
++              target_os = "openbsd"))]
++    #[test]
++    fn test_macos_tap_datalink_addr() {
++        let bytes = [20i8, 18, 7, 0, 6, 3, 6, 0, 101, 110, 48, 24, 101, -112, -35, 76, -80];
++        let ptr = bytes.as_ptr();
++        let sa = ptr as *const libc::sockaddr;
++        let _sock_addr = unsafe { SockAddr::from_libc_sockaddr(sa) };
++
++        assert!(_sock_addr.is_some());
++
++        let sock_addr = _sock_addr.unwrap();
++
++        assert_eq!(sock_addr.family(), AddressFamily::Link);
++
++        match sock_addr {
++            SockAddr::Link(ether_addr) => {
++                assert_eq!(ether_addr.addr(), [24u8, 101, 144, 221, 76, 176]);
++            },
++            _ => { unreachable!() }
++        };
++    }
++
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    #[test]
++    fn test_abstract_sun_path() {
++        let name = String::from("nix\0abstract\0test");
++        let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap();
++
++        let sun_path1 = addr.sun_path();
++        let sun_path2 = [0u8, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
++        assert_eq!(sun_path1.len(), sun_path2.len());
++        for i in 0..sun_path1.len() {
++            assert_eq!(sun_path1[i], sun_path2[i]);
++        }
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/socket/mod.rs b/third_party/rust/nix-0.15.0/src/sys/socket/mod.rs
+new file mode 100644
+index 0000000000000..1c12c5f851734
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/socket/mod.rs
+@@ -0,0 +1,1294 @@
++//! Socket interface functions
++//!
++//! [Further reading](http://man7.org/linux/man-pages/man7/socket.7.html)
++use {Error, Result};
++use errno::Errno;
++use libc::{self, c_void, c_int, iovec, socklen_t, size_t,
++        CMSG_FIRSTHDR, CMSG_NXTHDR, CMSG_DATA, CMSG_LEN};
++use std::{mem, ptr, slice};
++use std::os::unix::io::RawFd;
++use sys::time::TimeVal;
++use sys::uio::IoVec;
++
++mod addr;
++pub mod sockopt;
++
++/*
++ *
++ * ===== Re-exports =====
++ *
++ */
++
++pub use self::addr::{
++    AddressFamily,
++    SockAddr,
++    InetAddr,
++    UnixAddr,
++    IpAddr,
++    Ipv4Addr,
++    Ipv6Addr,
++    LinkAddr,
++};
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub use ::sys::socket::addr::netlink::NetlinkAddr;
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub use sys::socket::addr::alg::AlgAddr;
++#[cfg(target_os = "linux")]
++pub use sys::socket::addr::vsock::VsockAddr;
++
++pub use libc::{
++    cmsghdr,
++    msghdr,
++    sa_family_t,
++    sockaddr,
++    sockaddr_in,
++    sockaddr_in6,
++    sockaddr_storage,
++    sockaddr_un,
++};
++
++// Needed by the cmsg_space macro
++#[doc(hidden)]
++pub use libc::{c_uint, CMSG_SPACE};
++
++/// These constants are used to specify the communication semantics
++/// when creating a socket with [`socket()`](fn.socket.html)
++#[derive(Clone, Copy, PartialEq, Eq, Debug)]
++#[repr(i32)]
++pub enum SockType {
++    /// Provides sequenced, reliable, two-way, connection-
++    /// based byte streams.  An out-of-band data transmission
++    /// mechanism may be supported.
++    Stream = libc::SOCK_STREAM,
++    /// Supports datagrams (connectionless, unreliable
++    /// messages of a fixed maximum length).
++    Datagram = libc::SOCK_DGRAM,
++    /// Provides a sequenced, reliable, two-way connection-
++    /// based data transmission path for datagrams of fixed
++    /// maximum length; a consumer is required to read an
++    /// entire packet with each input system call.
++    SeqPacket = libc::SOCK_SEQPACKET,
++    /// Provides raw network protocol access.
++    Raw = libc::SOCK_RAW,
++    /// Provides a reliable datagram layer that does not
++    /// guarantee ordering.
++    Rdm = libc::SOCK_RDM,
++}
++
++/// Constants used in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html)
++/// to specify the protocol to use.
++#[repr(i32)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub enum SockProtocol {
++    /// TCP protocol ([ip(7)](http://man7.org/linux/man-pages/man7/ip.7.html))
++    Tcp = libc::IPPROTO_TCP,
++    /// UDP protocol ([ip(7)](http://man7.org/linux/man-pages/man7/ip.7.html))
++    Udp = libc::IPPROTO_UDP,
++    /// Allows applications and other KEXTs to be notified when certain kernel events occur
++    /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html))
++    #[cfg(any(target_os = "ios", target_os = "macos"))]
++    KextEvent = libc::SYSPROTO_EVENT,
++    /// Allows applications to configure and control a KEXT
++    /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html))
++    #[cfg(any(target_os = "ios", target_os = "macos"))]
++    KextControl = libc::SYSPROTO_CONTROL,
++}
++
++libc_bitflags!{
++    /// Additional socket options
++    pub struct SockFlag: c_int {
++        /// Set non-blocking mode on the new socket
++        #[cfg(any(target_os = "android",
++                  target_os = "dragonfly",
++                  target_os = "freebsd",
++                  target_os = "linux",
++                  target_os = "netbsd",
++                  target_os = "openbsd"))]
++        SOCK_NONBLOCK;
++        /// Set close-on-exec on the new descriptor
++        #[cfg(any(target_os = "android",
++                  target_os = "dragonfly",
++                  target_os = "freebsd",
++                  target_os = "linux",
++                  target_os = "netbsd",
++                  target_os = "openbsd"))]
++        SOCK_CLOEXEC;
++        /// Return `EPIPE` instead of raising `SIGPIPE`
++        #[cfg(target_os = "netbsd")]
++        SOCK_NOSIGPIPE;
++        /// For domains `AF_INET(6)`, only allow `connect(2)`, `sendto(2)`, or `sendmsg(2)`
++        /// to the DNS port (typically 53)
++        #[cfg(target_os = "openbsd")]
++        SOCK_DNS;
++    }
++}
++
++libc_bitflags!{
++    /// Flags for send/recv and their relatives
++    pub struct MsgFlags: c_int {
++        /// Sends or requests out-of-band data on sockets that support this notion
++        /// (e.g., of type [`Stream`](enum.SockType.html)); the underlying protocol must also
++        /// support out-of-band data.
++        MSG_OOB;
++        /// Peeks at an incoming message. The data is treated as unread and the next
++        /// [`recv()`](fn.recv.html)
++        /// or similar function shall still return this data.
++        MSG_PEEK;
++        /// Receive operation blocks until the full amount of data can be
++        /// returned. The function may return smaller amount of data if a signal
++        /// is caught, an error or disconnect occurs.
++        MSG_WAITALL;
++        /// Enables nonblocking operation; if the operation would block,
++        /// `EAGAIN` or `EWOULDBLOCK` is returned.  This provides similar
++        /// behavior to setting the `O_NONBLOCK` flag
++        /// (via the [`fcntl`](../../fcntl/fn.fcntl.html)
++        /// `F_SETFL` operation), but differs in that `MSG_DONTWAIT` is a per-
++        /// call option, whereas `O_NONBLOCK` is a setting on the open file
++        /// description (see [open(2)](http://man7.org/linux/man-pages/man2/open.2.html)),
++        /// which will affect all threads in
++        /// the calling process and as well as other processes that hold
++        /// file descriptors referring to the same open file description.
++        MSG_DONTWAIT;
++        /// Receive flags: Control Data was discarded (buffer too small)
++        MSG_CTRUNC;
++        /// For raw ([`Packet`](addr/enum.AddressFamily.html)), Internet datagram
++        /// (since Linux 2.4.27/2.6.8),
++        /// netlink (since Linux 2.6.22) and UNIX datagram (since Linux 3.4)
++        /// sockets: return the real length of the packet or datagram, even
++        /// when it was longer than the passed buffer. Not implemented for UNIX
++        /// domain ([unix(7)](https://linux.die.net/man/7/unix)) sockets.
++        ///
++        /// For use with Internet stream sockets, see [tcp(7)](https://linux.die.net/man/7/tcp).
++        MSG_TRUNC;
++        /// Terminates a record (when this notion is supported, as for
++        /// sockets of type [`SeqPacket`](enum.SockType.html)).
++        MSG_EOR;
++        /// This flag specifies that queued errors should be received from
++        /// the socket error queue. (For more details, see
++        /// [recvfrom(2)](https://linux.die.net/man/2/recvfrom))
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        MSG_ERRQUEUE;
++        /// Set the `close-on-exec` flag for the file descriptor received via a UNIX domain
++        /// file descriptor using the `SCM_RIGHTS` operation (described in
++        /// [unix(7)](https://linux.die.net/man/7/unix)).
++        /// This flag is useful for the same reasons as the `O_CLOEXEC` flag of
++        /// [open(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html).
++        ///
++        /// Only used in [`recvmsg`](fn.recvmsg.html) function.
++        #[cfg(any(target_os = "android",
++                  target_os = "dragonfly",
++                  target_os = "freebsd",
++                  target_os = "linux",
++                  target_os = "netbsd",
++                  target_os = "openbsd"))]
++        MSG_CMSG_CLOEXEC;
++    }
++}
++
++cfg_if! {
++    if #[cfg(any(target_os = "android", target_os = "linux"))] {
++        /// Unix credentials of the sending process.
++        ///
++        /// This struct is used with the `SO_PEERCRED` ancillary message for UNIX sockets.
++        #[repr(C)]
++        #[derive(Clone, Copy, Debug, Eq, PartialEq)]
++        pub struct UnixCredentials(libc::ucred);
++
++        impl UnixCredentials {
++            /// Returns the process identifier
++            pub fn pid(&self) -> libc::pid_t {
++                self.0.pid
++            }
++
++            /// Returns the user identifier
++            pub fn uid(&self) -> libc::uid_t {
++                self.0.uid
++            }
++
++            /// Returns the group identifier
++            pub fn gid(&self) -> libc::gid_t {
++                self.0.gid
++            }
++        }
++
++        impl From<libc::ucred> for UnixCredentials {
++            fn from(cred: libc::ucred) -> Self {
++                UnixCredentials(cred)
++            }
++        }
++
++        impl Into<libc::ucred> for UnixCredentials {
++            fn into(self) -> libc::ucred {
++                self.0
++            }
++        }
++    }
++}
++
++/// Request for multicast socket operations
++///
++/// This is a wrapper type around `ip_mreq`.
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, PartialEq)]
++pub struct IpMembershipRequest(libc::ip_mreq);
++
++impl IpMembershipRequest {
++    /// Instantiate a new `IpMembershipRequest`
++    ///
++    /// If `interface` is `None`, then `Ipv4Addr::any()` will be used for the interface.
++    pub fn new(group: Ipv4Addr, interface: Option<Ipv4Addr>) -> Self {
++        IpMembershipRequest(libc::ip_mreq {
++            imr_multiaddr: group.0,
++            imr_interface: interface.unwrap_or_else(Ipv4Addr::any).0,
++        })
++    }
++}
++
++/// Request for ipv6 multicast socket operations
++///
++/// This is a wrapper type around `ipv6_mreq`.
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, PartialEq)]
++pub struct Ipv6MembershipRequest(libc::ipv6_mreq);
++
++impl Ipv6MembershipRequest {
++    /// Instantiate a new `Ipv6MembershipRequest`
++    pub fn new(group: Ipv6Addr) -> Self {
++        Ipv6MembershipRequest(libc::ipv6_mreq {
++            ipv6mr_multiaddr: group.0,
++            ipv6mr_interface: 0,
++        })
++    }
++}
++
++cfg_if! {
++    // Darwin and DragonFly BSD always align struct cmsghdr to 32-bit only.
++    if #[cfg(any(target_os = "dragonfly", target_os = "ios", target_os = "macos"))] {
++        type align_of_cmsg_data = u32;
++    } else {
++        type align_of_cmsg_data = size_t;
++    }
++}
++
++/// A type that can be used to store ancillary data received by
++/// [`recvmsg`](fn.recvmsg.html)
++pub trait CmsgBuffer {
++    fn as_bytes_mut(&mut self) -> &mut [u8];
++}
++
++/// Create a buffer large enough for storing some control messages as returned
++/// by [`recvmsg`](fn.recvmsg.html).
++///
++/// # Examples
++///
++/// ```
++/// # #[macro_use] extern crate nix;
++/// # use nix::sys::time::TimeVal;
++/// # use std::os::unix::io::RawFd;
++/// # fn main() {
++/// // Create a buffer for a `ControlMessageOwned::ScmTimestamp` message
++/// let _ = cmsg_space!(TimeVal);
++/// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message
++/// // with two file descriptors
++/// let _ = cmsg_space!([RawFd; 2]);
++/// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message
++/// // and a `ControlMessageOwned::ScmTimestamp` message
++/// let _ = cmsg_space!(RawFd, TimeVal);
++/// # }
++/// ```
++// Unfortunately, CMSG_SPACE isn't a const_fn, or else we could return a
++// stack-allocated array.
++#[macro_export]
++macro_rules! cmsg_space {
++    ( $( $x:ty ),* ) => {
++        {
++            use nix::sys::socket::{c_uint, CMSG_SPACE};
++            use std::mem;
++            let mut space = 0;
++            $(
++                // CMSG_SPACE is always safe
++                space += unsafe {
++                    CMSG_SPACE(mem::size_of::<$x>() as c_uint)
++                } as usize;
++            )*
++            let mut v = Vec::<u8>::with_capacity(space);
++            // safe because any bit pattern is a valid u8
++            unsafe {v.set_len(space)};
++            v
++        }
++    }
++}
++
++/// A structure used to make room in a cmsghdr passed to recvmsg. The
++/// size and alignment match that of a cmsghdr followed by a T, but the
++/// fields are not accessible, as the actual types will change on a call
++/// to recvmsg.
++///
++/// To make room for multiple messages, nest the type parameter with
++/// tuples:
++///
++/// ```
++/// use std::os::unix::io::RawFd;
++/// use nix::sys::socket::CmsgSpace;
++/// let cmsg: CmsgSpace<([RawFd; 3], CmsgSpace<[RawFd; 2]>)> = CmsgSpace::new();
++/// ```
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, PartialEq)]
++pub struct CmsgSpace<T> {
++    _hdr: cmsghdr,
++    _pad: [align_of_cmsg_data; 0],
++    _data: T,
++}
++
++impl<T> CmsgSpace<T> {
++    /// Create a CmsgSpace<T>. The structure is used only for space, so
++    /// the fields are uninitialized.
++    #[deprecated( since="0.14.0", note="Use the cmsg_space! macro instead")]
++    pub fn new() -> Self {
++        // Safe because the fields themselves aren't accessible.
++        unsafe { mem::uninitialized() }
++    }
++}
++
++impl<T> CmsgBuffer for CmsgSpace<T> {
++    fn as_bytes_mut(&mut self) -> &mut [u8] {
++        // Safe because nothing ever attempts to access CmsgSpace's fields
++        unsafe {
++            slice::from_raw_parts_mut(self as *mut CmsgSpace<T> as *mut u8,
++                                      mem::size_of::<Self>())
++        }
++    }
++}
++
++impl CmsgBuffer for Vec<u8> {
++    fn as_bytes_mut(&mut self) -> &mut [u8] {
++        &mut self[..]
++    }
++}
++
++#[derive(Clone, Copy, Debug, Eq, PartialEq)]
++pub struct RecvMsg<'a> {
++    pub bytes: usize,
++    cmsghdr: Option<&'a cmsghdr>,
++    pub address: Option<SockAddr>,
++    pub flags: MsgFlags,
++    mhdr: msghdr,
++}
++
++impl<'a> RecvMsg<'a> {
++    /// Iterate over the valid control messages pointed to by this
++    /// msghdr.
++    pub fn cmsgs(&self) -> CmsgIterator {
++        CmsgIterator {
++            cmsghdr: self.cmsghdr,
++            mhdr: &self.mhdr
++        }
++    }
++}
++
++#[derive(Clone, Copy, Debug, Eq, PartialEq)]
++pub struct CmsgIterator<'a> {
++    /// Control message buffer to decode from. Must adhere to cmsg alignment.
++    cmsghdr: Option<&'a cmsghdr>,
++    mhdr: &'a msghdr
++}
++
++impl<'a> Iterator for CmsgIterator<'a> {
++    type Item = ControlMessageOwned;
++
++    fn next(&mut self) -> Option<ControlMessageOwned> {
++        match self.cmsghdr {
++            None => None,   // No more messages
++            Some(hdr) => {
++                // Get the data.
++                // Safe if cmsghdr points to valid data returned by recvmsg(2)
++                let cm = unsafe { Some(ControlMessageOwned::decode_from(hdr))};
++                // Advance the internal pointer.  Safe if mhdr and cmsghdr point
++                // to valid data returned by recvmsg(2)
++                self.cmsghdr = unsafe {
++                    let p = CMSG_NXTHDR(self.mhdr as *const _, hdr as *const _);
++                    p.as_ref()
++                };
++                cm
++            }
++        }
++    }
++}
++
++/// A type-safe wrapper around a single control message, as used with
++/// [`recvmsg`](#fn.recvmsg).
++///
++/// [Further reading](http://man7.org/linux/man-pages/man3/cmsg.3.html)
++//  Nix version 0.13.0 and earlier used ControlMessage for both recvmsg and
++//  sendmsg.  However, on some platforms the messages returned by recvmsg may be
++//  unaligned.  ControlMessageOwned takes those messages by copy, obviating any
++//  alignment issues.
++//
++//  See https://github.com/nix-rust/nix/issues/999
++#[derive(Clone, Debug, Eq, PartialEq)]
++pub enum ControlMessageOwned {
++    /// Received version of
++    /// [`ControlMessage::ScmRights`][#enum.ControlMessage.html#variant.ScmRights]
++    ScmRights(Vec<RawFd>),
++    /// Received version of
++    /// [`ControlMessage::ScmCredentials`][#enum.ControlMessage.html#variant.ScmCredentials]
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    ScmCredentials(libc::ucred),
++    /// A message of type `SCM_TIMESTAMP`, containing the time the
++    /// packet was received by the kernel.
++    ///
++    /// See the kernel's explanation in "SO_TIMESTAMP" of
++    /// [networking/timestamping](https://www.kernel.org/doc/Documentation/networking/timestamping.txt).
++    ///
++    /// # Examples
++    ///
++    // Disable this test on FreeBSD i386
++    // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=222039
++    #[cfg_attr(not(all(target_os = "freebsd", target_arch = "x86")), doc = " ```")]
++    #[cfg_attr(all(target_os = "freebsd", target_arch = "x86"), doc = " ```no_run")]
++    /// # #[macro_use] extern crate nix;
++    /// # use nix::sys::socket::*;
++    /// # use nix::sys::uio::IoVec;
++    /// # use nix::sys::time::*;
++    /// # use std::time::*;
++    /// # fn main() {
++    /// // Set up
++    /// let message = "Ohayō!".as_bytes();
++    /// let in_socket = socket(
++    ///     AddressFamily::Inet,
++    ///     SockType::Datagram,
++    ///     SockFlag::empty(),
++    ///     None).unwrap();
++    /// setsockopt(in_socket, sockopt::ReceiveTimestamp, &true).unwrap();
++    /// let localhost = InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0);
++    /// bind(in_socket, &SockAddr::new_inet(localhost)).unwrap();
++    /// let address = getsockname(in_socket).unwrap();
++    /// // Get initial time
++    /// let time0 = SystemTime::now();
++    /// // Send the message
++    /// let iov = [IoVec::from_slice(message)];
++    /// let flags = MsgFlags::empty();
++    /// let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap();
++    /// assert_eq!(message.len(), l);
++    /// // Receive the message
++    /// let mut buffer = vec![0u8; message.len()];
++    /// let mut cmsgspace = cmsg_space!(TimeVal);
++    /// let iov = [IoVec::from_mut_slice(&mut buffer)];
++    /// let r = recvmsg(in_socket, &iov, Some(&mut cmsgspace), flags).unwrap();
++    /// let rtime = match r.cmsgs().next() {
++    ///     Some(ControlMessageOwned::ScmTimestamp(rtime)) => rtime,
++    ///     Some(_) => panic!("Unexpected control message"),
++    ///     None => panic!("No control message")
++    /// };
++    /// // Check the final time
++    /// let time1 = SystemTime::now();
++    /// // the packet's received timestamp should lie in-between the two system
++    /// // times, unless the system clock was adjusted in the meantime.
++    /// let rduration = Duration::new(rtime.tv_sec() as u64,
++    ///                               rtime.tv_usec() as u32 * 1000);
++    /// assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration);
++    /// assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap());
++    /// // Close socket
++    /// nix::unistd::close(in_socket).unwrap();
++    /// # }
++    /// ```
++    ScmTimestamp(TimeVal),
++    #[cfg(any(
++        target_os = "android",
++        target_os = "ios",
++        target_os = "linux",
++        target_os = "macos",
++        target_os = "netbsd",
++    ))]
++    Ipv4PacketInfo(libc::in_pktinfo),
++    #[cfg(any(
++        target_os = "android",
++        target_os = "dragonfly",
++        target_os = "freebsd",
++        target_os = "ios",
++        target_os = "linux",
++        target_os = "macos",
++        target_os = "openbsd",
++        target_os = "netbsd",
++    ))]
++    Ipv6PacketInfo(libc::in6_pktinfo),
++    #[cfg(any(
++        target_os = "freebsd",
++        target_os = "ios",
++        target_os = "macos",
++        target_os = "netbsd",
++        target_os = "openbsd",
++    ))]
++    Ipv4RecvIf(libc::sockaddr_dl),
++    #[cfg(any(
++        target_os = "freebsd",
++        target_os = "ios",
++        target_os = "macos",
++        target_os = "netbsd",
++        target_os = "openbsd",
++    ))]
++    Ipv4RecvDstAddr(libc::in_addr),
++    /// Catch-all variant for unimplemented cmsg types.
++    #[doc(hidden)]
++    Unknown(UnknownCmsg),
++}
++
++impl ControlMessageOwned {
++    /// Decodes a `ControlMessageOwned` from raw bytes.
++    ///
++    /// This is only safe to call if the data is correct for the message type
++    /// specified in the header. Normally, the kernel ensures that this is the
++    /// case. "Correct" in this case includes correct length, alignment and
++    /// actual content.
++    ///
++    /// Returns `None` if the data may be unaligned.  In that case use
++    /// `ControlMessageOwned::decode_from`.
++    unsafe fn decode_from(header: &cmsghdr) -> ControlMessageOwned
++    {
++        let p = CMSG_DATA(header);
++        let len = header as *const _ as usize + header.cmsg_len as usize
++            - p as usize;
++        match (header.cmsg_level, header.cmsg_type) {
++            (libc::SOL_SOCKET, libc::SCM_RIGHTS) => {
++                let n = len / mem::size_of::<RawFd>();
++                let mut fds = Vec::with_capacity(n);
++                for i in 0..n {
++                    let fdp = (p as *const RawFd).offset(i as isize);
++                    fds.push(ptr::read_unaligned(fdp));
++                }
++                let cmo = ControlMessageOwned::ScmRights(fds);
++                cmo
++            },
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            (libc::SOL_SOCKET, libc::SCM_CREDENTIALS) => {
++                let cred: libc::ucred = ptr::read_unaligned(p as *const _);
++                ControlMessageOwned::ScmCredentials(cred)
++            }
++            (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => {
++                let tv: libc::timeval = ptr::read_unaligned(p as *const _);
++                ControlMessageOwned::ScmTimestamp(TimeVal::from(tv))
++            },
++            #[cfg(any(
++                target_os = "android",
++                target_os = "freebsd",
++                target_os = "ios",
++                target_os = "linux",
++                target_os = "macos"
++            ))]
++            (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => {
++                let info = ptr::read_unaligned(p as *const libc::in6_pktinfo);
++                ControlMessageOwned::Ipv6PacketInfo(info)
++            }
++            #[cfg(any(
++                target_os = "android",
++                target_os = "ios",
++                target_os = "linux",
++                target_os = "macos",
++                target_os = "netbsd",
++            ))]
++            (libc::IPPROTO_IP, libc::IP_PKTINFO) => {
++                let info = ptr::read_unaligned(p as *const libc::in_pktinfo);
++                ControlMessageOwned::Ipv4PacketInfo(info)
++            }
++            #[cfg(any(
++                target_os = "freebsd",
++                target_os = "ios",
++                target_os = "macos",
++                target_os = "netbsd",
++                target_os = "openbsd",
++            ))]
++            (libc::IPPROTO_IP, libc::IP_RECVIF) => {
++                let dl = ptr::read_unaligned(p as *const libc::sockaddr_dl);
++                ControlMessageOwned::Ipv4RecvIf(dl)
++            },
++            #[cfg(any(
++                target_os = "freebsd",
++                target_os = "ios",
++                target_os = "macos",
++                target_os = "netbsd",
++                target_os = "openbsd",
++            ))]
++            (libc::IPPROTO_IP, libc::IP_RECVDSTADDR) => {
++                let dl = ptr::read_unaligned(p as *const libc::in_addr);
++                ControlMessageOwned::Ipv4RecvDstAddr(dl)
++            },
++            (_, _) => {
++                let sl = slice::from_raw_parts(p, len);
++                let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(&sl[..]));
++                ControlMessageOwned::Unknown(ucmsg)
++            }
++        }
++    }
++}
++
++/// A type-safe zero-copy wrapper around a single control message, as used wih
++/// [`sendmsg`](#fn.sendmsg).  More types may be added to this enum; do not
++/// exhaustively pattern-match it.
++///
++/// [Further reading](http://man7.org/linux/man-pages/man3/cmsg.3.html)
++#[derive(Clone, Copy, Debug, Eq, PartialEq)]
++pub enum ControlMessage<'a> {
++    /// A message of type `SCM_RIGHTS`, containing an array of file
++    /// descriptors passed between processes.
++    ///
++    /// See the description in the "Ancillary messages" section of the
++    /// [unix(7) man page](http://man7.org/linux/man-pages/man7/unix.7.html).
++    ///
++    /// Using multiple `ScmRights` messages for a single `sendmsg` call isn't
++    /// recommended since it causes platform-dependent behaviour: It might
++    /// swallow all but the first `ScmRights` message or fail with `EINVAL`.
++    /// Instead, you can put all fds to be passed into a single `ScmRights`
++    /// message.
++    ScmRights(&'a [RawFd]),
++    /// A message of type `SCM_CREDENTIALS`, containing the pid, uid and gid of
++    /// a process connected to the socket.
++    ///
++    /// This is similar to the socket option `SO_PEERCRED`, but requires a
++    /// process to explicitly send its credentials. A process running as root is
++    /// allowed to specify any credentials, while credentials sent by other
++    /// processes are verified by the kernel.
++    ///
++    /// For further information, please refer to the
++    /// [`unix(7)`](http://man7.org/linux/man-pages/man7/unix.7.html) man page.
++    // FIXME: When `#[repr(transparent)]` is stable, use it on `UnixCredentials`
++    // and put that in here instead of a raw ucred.
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    ScmCredentials(&'a libc::ucred),
++
++    /// Set IV for `AF_ALG` crypto API.
++    ///
++    /// For further information, please refer to the
++    /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
++    #[cfg(any(
++        target_os = "android",
++        target_os = "linux",
++    ))]
++    AlgSetIv(&'a [u8]),
++    /// Set crypto operation for `AF_ALG` crypto API. It may be one of
++    /// `ALG_OP_ENCRYPT` or `ALG_OP_DECRYPT`
++    ///
++    /// For further information, please refer to the
++    /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
++    #[cfg(any(
++        target_os = "android",
++        target_os = "linux",
++    ))]
++    AlgSetOp(&'a libc::c_int),
++    /// Set the length of associated authentication data (AAD) (applicable only to AEAD algorithms)
++    /// for `AF_ALG` crypto API.
++    ///
++    /// For further information, please refer to the
++    /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
++    #[cfg(any(
++        target_os = "android",
++        target_os = "linux",
++    ))]
++    AlgSetAeadAssoclen(&'a u32),
++
++}
++
++// An opaque structure used to prevent cmsghdr from being a public type
++#[doc(hidden)]
++#[derive(Clone, Debug, Eq, PartialEq)]
++pub struct UnknownCmsg(cmsghdr, Vec<u8>);
++
++impl<'a> ControlMessage<'a> {
++    /// The value of CMSG_SPACE on this message.
++    /// Safe because CMSG_SPACE is always safe
++    fn space(&self) -> usize {
++        unsafe{CMSG_SPACE(self.len() as libc::c_uint) as usize}
++    }
++
++    /// The value of CMSG_LEN on this message.
++    /// Safe because CMSG_LEN is always safe
++    #[cfg(any(target_os = "android",
++              all(target_os = "linux", not(target_env = "musl"))))]
++    fn cmsg_len(&self) -> usize {
++        unsafe{CMSG_LEN(self.len() as libc::c_uint) as usize}
++    }
++
++    #[cfg(not(any(target_os = "android",
++                  all(target_os = "linux", not(target_env = "musl")))))]
++    fn cmsg_len(&self) -> libc::c_uint {
++        unsafe{CMSG_LEN(self.len() as libc::c_uint)}
++    }
++
++    /// Return a reference to the payload data as a byte pointer
++    fn copy_to_cmsg_data(&self, cmsg_data: *mut u8) {
++        let data_ptr = match self {
++            &ControlMessage::ScmRights(fds) => {
++                fds as *const _ as *const u8
++            },
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            &ControlMessage::ScmCredentials(creds) => {
++                creds as *const libc::ucred as *const u8
++            }
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            &ControlMessage::AlgSetIv(iv) => {
++                unsafe {
++                    let alg_iv = cmsg_data as *mut libc::af_alg_iv;
++                    (*alg_iv).ivlen = iv.len() as u32;
++                    ptr::copy_nonoverlapping(
++                        iv.as_ptr(),
++                        (*alg_iv).iv.as_mut_ptr(),
++                        iv.len()
++                    );
++                };
++                return
++            },
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            &ControlMessage::AlgSetOp(op) => {
++                op as *const _ as *const u8
++            },
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            &ControlMessage::AlgSetAeadAssoclen(len) => {
++                len as *const _ as *const u8
++            },
++        };
++        unsafe {
++            ptr::copy_nonoverlapping(
++                data_ptr,
++                cmsg_data,
++                self.len()
++            )
++        };
++    }
++
++    /// The size of the payload, excluding its cmsghdr
++    fn len(&self) -> usize {
++        match self {
++            &ControlMessage::ScmRights(fds) => {
++                mem::size_of_val(fds)
++            },
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            &ControlMessage::ScmCredentials(creds) => {
++                mem::size_of_val(creds)
++            }
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            &ControlMessage::AlgSetIv(iv) => {
++                mem::size_of::<libc::af_alg_iv>() + iv.len()
++            },
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            &ControlMessage::AlgSetOp(op) => {
++                mem::size_of_val(op)
++            },
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            &ControlMessage::AlgSetAeadAssoclen(len) => {
++                mem::size_of_val(len)
++            },
++        }
++    }
++
++    /// Returns the value to put into the `cmsg_level` field of the header.
++    fn cmsg_level(&self) -> libc::c_int {
++        match self {
++            &ControlMessage::ScmRights(_) => libc::SOL_SOCKET,
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            &ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET,
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            &ControlMessage::AlgSetIv(_) | &ControlMessage::AlgSetOp(_) | &ControlMessage::AlgSetAeadAssoclen(_) => {
++                libc::SOL_ALG
++            },
++        }
++    }
++
++    /// Returns the value to put into the `cmsg_type` field of the header.
++    fn cmsg_type(&self) -> libc::c_int {
++        match self {
++            &ControlMessage::ScmRights(_) => libc::SCM_RIGHTS,
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            &ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS,
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            &ControlMessage::AlgSetIv(_) => {
++                libc::ALG_SET_IV
++            },
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            &ControlMessage::AlgSetOp(_) => {
++                libc::ALG_SET_OP
++            },
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            &ControlMessage::AlgSetAeadAssoclen(_) => {
++                libc::ALG_SET_AEAD_ASSOCLEN
++            },
++        }
++    }
++
++    // Unsafe: cmsg must point to a valid cmsghdr with enough space to
++    // encode self.
++    unsafe fn encode_into(&self, cmsg: *mut cmsghdr) {
++        (*cmsg).cmsg_level = self.cmsg_level();
++        (*cmsg).cmsg_type = self.cmsg_type();
++        (*cmsg).cmsg_len = self.cmsg_len();
++        self.copy_to_cmsg_data(CMSG_DATA(cmsg));
++    }
++}
++
++
++/// Send data in scatter-gather vectors to a socket, possibly accompanied
++/// by ancillary data. Optionally direct the message at the given address,
++/// as with sendto.
++///
++/// Allocates if cmsgs is nonempty.
++pub fn sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage],
++               flags: MsgFlags, addr: Option<&SockAddr>) -> Result<usize>
++{
++    let capacity = cmsgs.iter().map(|c| c.space()).sum();
++
++    // First size the buffer needed to hold the cmsgs.  It must be zeroed,
++    // because subsequent code will not clear the padding bytes.
++    let cmsg_buffer = vec![0u8; capacity];
++
++    // Next encode the sending address, if provided
++    let (name, namelen) = match addr {
++        Some(addr) => {
++            let (x, y) = unsafe { addr.as_ffi_pair() };
++            (x as *const _, y)
++        },
++        None => (ptr::null(), 0),
++    };
++
++    // The message header must be initialized before the individual cmsgs.
++    let cmsg_ptr = if capacity > 0 {
++        cmsg_buffer.as_ptr() as *mut c_void
++    } else {
++        ptr::null_mut()
++    };
++
++    let mhdr = {
++        // Musl's msghdr has private fields, so this is the only way to
++        // initialize it.
++        let mut mhdr: msghdr = unsafe{mem::uninitialized()};
++        mhdr.msg_name = name as *mut _;
++        mhdr.msg_namelen = namelen;
++        // transmute iov into a mutable pointer.  sendmsg doesn't really mutate
++        // the buffer, but the standard says that it takes a mutable pointer
++        mhdr.msg_iov = iov.as_ptr() as *mut _;
++        mhdr.msg_iovlen = iov.len() as _;
++        mhdr.msg_control = cmsg_ptr;
++        mhdr.msg_controllen = capacity as _;
++        mhdr.msg_flags = 0;
++        mhdr
++    };
++
++    // Encode each cmsg.  This must happen after initializing the header because
++    // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields.
++    // CMSG_FIRSTHDR is always safe
++    let mut pmhdr: *mut cmsghdr = unsafe{CMSG_FIRSTHDR(&mhdr as *const msghdr)};
++    for cmsg in cmsgs {
++        assert_ne!(pmhdr, ptr::null_mut());
++        // Safe because we know that pmhdr is valid, and we initialized it with
++        // sufficient space
++        unsafe { cmsg.encode_into(pmhdr) };
++        // Safe because mhdr is valid
++        pmhdr = unsafe{CMSG_NXTHDR(&mhdr as *const msghdr, pmhdr)};
++    }
++
++    let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) };
++
++    Errno::result(ret).map(|r| r as usize)
++}
++
++/// Receive message in scatter-gather vectors from a socket, and
++/// optionally receive ancillary data into the provided buffer.
++/// If no ancillary data is desired, use () as the type parameter.
++///
++/// # References
++/// [recvmsg(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html)
++pub fn recvmsg<'a>(fd: RawFd, iov: &[IoVec<&mut [u8]>],
++                   cmsg_buffer: Option<&'a mut dyn CmsgBuffer>,
++                   flags: MsgFlags) -> Result<RecvMsg<'a>>
++{
++    let mut address: sockaddr_storage = unsafe { mem::uninitialized() };
++    let (msg_control, msg_controllen) = match cmsg_buffer {
++        Some(cmsgspace) => {
++            let msg_buf = cmsgspace.as_bytes_mut();
++            (msg_buf.as_mut_ptr(), msg_buf.len())
++        },
++        None => (ptr::null_mut(), 0),
++    };
++    let mut mhdr = {
++        // Musl's msghdr has private fields, so this is the only way to
++        // initialize it.
++        let mut mhdr: msghdr = unsafe{mem::uninitialized()};
++        mhdr.msg_name = &mut address as *mut sockaddr_storage as *mut c_void;
++        mhdr.msg_namelen = mem::size_of::<sockaddr_storage>() as socklen_t;
++        mhdr.msg_iov = iov.as_ptr() as *mut iovec;
++        mhdr.msg_iovlen = iov.len() as _;
++        mhdr.msg_control = msg_control as *mut c_void;
++        mhdr.msg_controllen = msg_controllen as _;
++        mhdr.msg_flags = 0;
++        mhdr
++    };
++
++    let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) };
++
++    Errno::result(ret).map(|r| {
++        let cmsghdr = unsafe {
++            if mhdr.msg_controllen > 0 {
++                // got control message(s)
++                debug_assert!(!mhdr.msg_control.is_null());
++                debug_assert!(msg_controllen >= mhdr.msg_controllen as usize);
++                CMSG_FIRSTHDR(&mhdr as *const msghdr)
++            } else {
++                ptr::null()
++            }.as_ref()
++        };
++
++        let address = unsafe {
++            sockaddr_storage_to_addr(&address, mhdr.msg_namelen as usize).ok()
++        };
++        RecvMsg {
++            bytes: r as usize,
++            cmsghdr,
++            address,
++            flags: MsgFlags::from_bits_truncate(mhdr.msg_flags),
++            mhdr,
++        }
++    })
++}
++
++
++/// Create an endpoint for communication
++///
++/// The `protocol` specifies a particular protocol to be used with the
++/// socket.  Normally only a single protocol exists to support a
++/// particular socket type within a given protocol family, in which case
++/// protocol can be specified as `None`.  However, it is possible that many
++/// protocols may exist, in which case a particular protocol must be
++/// specified in this manner.
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html)
++pub fn socket<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, flags: SockFlag, protocol: T) -> Result<RawFd> {
++    let protocol = match protocol.into() {
++        None => 0,
++        Some(p) => p as c_int,
++    };
++
++    // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a
++    // little easier to understand by separating it out. So we have to merge these bitfields
++    // here.
++    let mut ty = ty as c_int;
++    ty |= flags.bits();
++
++    let res = unsafe { libc::socket(domain as c_int, ty, protocol) };
++
++    Errno::result(res)
++}
++
++/// Create a pair of connected sockets
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html)
++pub fn socketpair<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, protocol: T,
++                  flags: SockFlag) -> Result<(RawFd, RawFd)> {
++    let protocol = match protocol.into() {
++        None => 0,
++        Some(p) => p as c_int,
++    };
++
++    // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a
++    // little easier to understand by separating it out. So we have to merge these bitfields
++    // here.
++    let mut ty = ty as c_int;
++    ty |= flags.bits();
++
++    let mut fds = [-1, -1];
++
++    let res = unsafe { libc::socketpair(domain as c_int, ty, protocol, fds.as_mut_ptr()) };
++    Errno::result(res)?;
++
++    Ok((fds[0], fds[1]))
++}
++
++/// Listen for connections on a socket
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html)
++pub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> {
++    let res = unsafe { libc::listen(sockfd, backlog as c_int) };
++
++    Errno::result(res).map(drop)
++}
++
++/// Bind a name to a socket
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html)
++pub fn bind(fd: RawFd, addr: &SockAddr) -> Result<()> {
++    let res = unsafe {
++        let (ptr, len) = addr.as_ffi_pair();
++        libc::bind(fd, ptr, len)
++    };
++
++    Errno::result(res).map(drop)
++}
++
++/// Accept a connection on a socket
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html)
++pub fn accept(sockfd: RawFd) -> Result<RawFd> {
++    let res = unsafe { libc::accept(sockfd, ptr::null_mut(), ptr::null_mut()) };
++
++    Errno::result(res)
++}
++
++/// Accept a connection on a socket
++///
++/// [Further reading](http://man7.org/linux/man-pages/man2/accept.2.html)
++#[cfg(any(target_os = "android",
++          target_os = "freebsd",
++          target_os = "linux",
++          target_os = "openbsd"))]
++pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> {
++    let res = unsafe { libc::accept4(sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits()) };
++
++    Errno::result(res)
++}
++
++/// Initiate a connection on a socket
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html)
++pub fn connect(fd: RawFd, addr: &SockAddr) -> Result<()> {
++    let res = unsafe {
++        let (ptr, len) = addr.as_ffi_pair();
++        libc::connect(fd, ptr, len)
++    };
++
++    Errno::result(res).map(drop)
++}
++
++/// Receive data from a connection-oriented socket. Returns the number of
++/// bytes read
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html)
++pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> {
++    unsafe {
++        let ret = libc::recv(
++            sockfd,
++            buf.as_ptr() as *mut c_void,
++            buf.len() as size_t,
++            flags.bits());
++
++        Errno::result(ret).map(|r| r as usize)
++    }
++}
++
++/// Receive data from a connectionless or connection-oriented socket. Returns
++/// the number of bytes read and the socket address of the sender.
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html)
++pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) -> Result<(usize, SockAddr)> {
++    unsafe {
++        let addr: sockaddr_storage = mem::zeroed();
++        let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
++
++        let ret = Errno::result(libc::recvfrom(
++            sockfd,
++            buf.as_ptr() as *mut c_void,
++            buf.len() as size_t,
++            0,
++            mem::transmute(&addr),
++            &mut len as *mut socklen_t))?;
++
++        sockaddr_storage_to_addr(&addr, len as usize)
++            .map(|addr| (ret as usize, addr))
++    }
++}
++
++/// Send a message to a socket
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html)
++pub fn sendto(fd: RawFd, buf: &[u8], addr: &SockAddr, flags: MsgFlags) -> Result<usize> {
++    let ret = unsafe {
++        let (ptr, len) = addr.as_ffi_pair();
++        libc::sendto(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits(), ptr, len)
++    };
++
++    Errno::result(ret).map(|r| r as usize)
++}
++
++/// Send data to a connection-oriented socket. Returns the number of bytes read
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html)
++pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize> {
++    let ret = unsafe {
++        libc::send(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits())
++    };
++
++    Errno::result(ret).map(|r| r as usize)
++}
++
++/*
++ *
++ * ===== Socket Options =====
++ *
++ */
++
++/// The protocol level at which to get / set socket options. Used as an
++/// argument to `getsockopt` and `setsockopt`.
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html)
++#[repr(i32)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub enum SockLevel {
++    Socket = libc::SOL_SOCKET,
++    Tcp = libc::IPPROTO_TCP,
++    Ip = libc::IPPROTO_IP,
++    Ipv6 = libc::IPPROTO_IPV6,
++    Udp = libc::IPPROTO_UDP,
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    Netlink = libc::SOL_NETLINK,
++    #[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 {
++    type Val;
++
++    #[doc(hidden)]
++    fn get(&self, fd: RawFd) -> Result<Self::Val>;
++}
++
++/// Represents a socket option that can be accessed or set. Used as an argument
++/// to `setsockopt`
++pub trait SetSockOpt : Clone {
++    type Val;
++
++    #[doc(hidden)]
++    fn set(&self, fd: RawFd, val: &Self::Val) -> Result<()>;
++}
++
++/// Get the current value for the requested socket option
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html)
++pub fn getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val> {
++    opt.get(fd)
++}
++
++/// Sets the value for the requested socket option
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html)
++///
++/// # Examples
++///
++/// ```
++/// use nix::sys::socket::setsockopt;
++/// use nix::sys::socket::sockopt::KeepAlive;
++/// use std::net::TcpListener;
++/// use std::os::unix::io::AsRawFd;
++///
++/// let listener = TcpListener::bind("0.0.0.0:0").unwrap();
++/// let fd = listener.as_raw_fd();
++/// let res = setsockopt(fd, KeepAlive, &true);
++/// assert!(res.is_ok());
++/// ```
++pub fn setsockopt<O: SetSockOpt>(fd: RawFd, opt: O, val: &O::Val) -> Result<()> {
++    opt.set(fd, val)
++}
++
++/// Get the address of the peer connected to the socket `fd`.
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html)
++pub fn getpeername(fd: RawFd) -> Result<SockAddr> {
++    unsafe {
++        let addr: sockaddr_storage = mem::uninitialized();
++        let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
++
++        let ret = libc::getpeername(fd, mem::transmute(&addr), &mut len);
++
++        Errno::result(ret)?;
++
++        sockaddr_storage_to_addr(&addr, len as usize)
++    }
++}
++
++/// Get the current address to which the socket `fd` is bound.
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html)
++pub fn getsockname(fd: RawFd) -> Result<SockAddr> {
++    unsafe {
++        let addr: sockaddr_storage = mem::uninitialized();
++        let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
++
++        let ret = libc::getsockname(fd, mem::transmute(&addr), &mut len);
++
++        Errno::result(ret)?;
++
++        sockaddr_storage_to_addr(&addr, len as usize)
++    }
++}
++
++/// Return the appropriate `SockAddr` type from a `sockaddr_storage` of a certain
++/// size.  In C this would usually be done by casting.  The `len` argument
++/// should be the number of bytes in the `sockaddr_storage` that are actually
++/// allocated and valid.  It must be at least as large as all the useful parts
++/// of the structure.  Note that in the case of a `sockaddr_un`, `len` need not
++/// include the terminating null.
++pub unsafe fn sockaddr_storage_to_addr(
++    addr: &sockaddr_storage,
++    len: usize) -> Result<SockAddr> {
++
++    if len < mem::size_of_val(&addr.ss_family) {
++        return Err(Error::Sys(Errno::ENOTCONN));
++    }
++
++    match addr.ss_family as c_int {
++        libc::AF_INET => {
++            assert!(len as usize == mem::size_of::<sockaddr_in>());
++            let ret = *(addr as *const _ as *const sockaddr_in);
++            Ok(SockAddr::Inet(InetAddr::V4(ret)))
++        }
++        libc::AF_INET6 => {
++            assert!(len as usize == mem::size_of::<sockaddr_in6>());
++            Ok(SockAddr::Inet(InetAddr::V6(*(addr as *const _ as *const sockaddr_in6))))
++        }
++        libc::AF_UNIX => {
++            let sun = *(addr as *const _ as *const sockaddr_un);
++            let pathlen = len - offset_of!(sockaddr_un, sun_path);
++            Ok(SockAddr::Unix(UnixAddr(sun, pathlen)))
++        }
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        libc::AF_NETLINK => {
++            use libc::sockaddr_nl;
++            Ok(SockAddr::Netlink(NetlinkAddr(*(addr as *const _ as *const sockaddr_nl))))
++        }
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        libc::AF_ALG => {
++            use libc::sockaddr_alg;
++            Ok(SockAddr::Alg(AlgAddr(*(addr as *const _ as *const sockaddr_alg))))
++        }
++        #[cfg(target_os = "linux")]
++        libc::AF_VSOCK => {
++            use libc::sockaddr_vm;
++            Ok(SockAddr::Vsock(VsockAddr(*(addr as *const _ as *const sockaddr_vm))))
++        }
++        af => panic!("unexpected address family {}", af),
++    }
++}
++
++
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub enum Shutdown {
++    /// Further receptions will be disallowed.
++    Read,
++    /// Further  transmissions will be disallowed.
++    Write,
++    /// Further receptions and transmissions will be disallowed.
++    Both,
++}
++
++/// Shut down part of a full-duplex connection.
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html)
++pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> {
++    unsafe {
++        use libc::shutdown;
++
++        let how = match how {
++            Shutdown::Read  => libc::SHUT_RD,
++            Shutdown::Write => libc::SHUT_WR,
++            Shutdown::Both  => libc::SHUT_RDWR,
++        };
++
++        Errno::result(shutdown(df, how)).map(drop)
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/socket/sockopt.rs b/third_party/rust/nix-0.15.0/src/sys/socket/sockopt.rs
+new file mode 100644
+index 0000000000000..a996010018d5b
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/socket/sockopt.rs
+@@ -0,0 +1,680 @@
++use super::{GetSockOpt, SetSockOpt};
++use Result;
++use errno::Errno;
++use sys::time::TimeVal;
++use libc::{self, c_int, c_void, socklen_t};
++use std::mem;
++use std::os::unix::io::RawFd;
++use std::ffi::{OsStr, OsString};
++#[cfg(target_family = "unix")]
++use std::os::unix::ffi::OsStrExt;
++
++// Constants
++// TCP_CA_NAME_MAX isn't defined in user space include files
++#[cfg(any(target_os = "freebsd", target_os = "linux"))] 
++const TCP_CA_NAME_MAX: usize = 16;
++
++/// Helper for implementing `SetSockOpt` for a given socket option. See
++/// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html).
++///
++/// This macro aims to help implementing `SetSockOpt` for different socket options that accept
++/// different kinds of data to be used with `setsockopt`.
++///
++/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option
++/// you are implementing represents a simple type.
++///
++/// # Arguments
++///
++/// * `$name:ident`: name of the type you want to implement `SetSockOpt` for.
++/// * `$level:path` : socket layer, or a `protocol level`: could be *raw sockets*
++///    (`libc::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),
++///    and more. Please refer to your system manual for more options. Will be passed as the second
++///    argument (`level`) to the `setsockopt` call.
++/// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
++///    `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`)
++///    to the `setsockopt` call.
++/// * Type of the value that you are going to set.
++/// * Type that implements the `Set` trait for the type from the previous item (like `SetBool` for
++///    `bool`, `SetUsize` for `usize`, etc.).
++macro_rules! setsockopt_impl {
++    ($name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
++        impl SetSockOpt for $name {
++            type Val = $ty;
++
++            fn set(&self, fd: RawFd, val: &$ty) -> Result<()> {
++                unsafe {
++                    let setter: $setter = Set::new(val);
++
++                    let res = libc::setsockopt(fd, $level, $flag,
++                                               setter.ffi_ptr(),
++                                               setter.ffi_len());
++                    Errno::result(res).map(drop)
++                }
++            }
++        }
++    }
++}
++
++/// Helper for implementing `GetSockOpt` for a given socket option. See
++/// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html).
++///
++/// This macro aims to help implementing `GetSockOpt` for different socket options that accept
++/// different kinds of data to be use with `getsockopt`.
++///
++/// Instead of using this macro directly consider using `sockopt_impl!`, especially if the option
++/// you are implementing represents a simple type.
++///
++/// # Arguments
++///
++/// * Name of the type you want to implement `GetSockOpt` for.
++/// * Socket layer, or a `protocol level`: could be *raw sockets* (`lic::SOL_SOCKET`),  *ip
++///    protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),  and more. Please refer
++///    to your system manual for more options. Will be passed as the second argument (`level`) to
++///    the `getsockopt` call.
++/// * A flag to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
++///    `libc::SO_ORIGINAL_DST` and others. Will be passed as the third argument (`option_name`) to
++///    the `getsockopt` call.
++/// * Type of the value that you are going to get.
++/// * Type that implements the `Get` trait for the type from the previous item (`GetBool` for
++///    `bool`, `GetUsize` for `usize`, etc.).
++macro_rules! getsockopt_impl {
++    ($name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
++        impl GetSockOpt for $name {
++            type Val = $ty;
++
++            fn get(&self, fd: RawFd) -> Result<$ty> {
++                unsafe {
++                    let mut getter: $getter = Get::blank();
++
++                    let res = libc::getsockopt(fd, $level, $flag,
++                                               getter.ffi_ptr(),
++                                               getter.ffi_len());
++                    Errno::result(res)?;
++
++                    Ok(getter.unwrap())
++                }
++            }
++        }
++    }
++}
++
++/// Helper to generate the sockopt accessors. See
++/// [`::sys::socket::GetSockOpt`](sys/socket/trait.GetSockOpt.html) and
++/// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html).
++///
++/// This macro aims to help implementing `GetSockOpt` and `SetSockOpt` for different socket options
++/// that accept different kinds of data to be use with `getsockopt` and `setsockopt` respectively.
++///
++/// Basically this macro wraps up the [`getsockopt_impl!`](macro.getsockopt_impl.html) and
++/// [`setsockopt_impl!`](macro.setsockopt_impl.html) macros.
++///
++/// # Arguments
++///
++/// * `GetOnly`, `SetOnly` or `Both`: whether you want to implement only getter, only setter or
++///    both of them.
++/// * `$name:ident`: name of type `GetSockOpt`/`SetSockOpt` will be implemented for.
++/// * `$level:path` : socket layer, or a `protocol level`: could be *raw sockets*
++///    (`lic::SOL_SOCKET`), *ip protocol* (libc::IPPROTO_IP), *tcp protocol* (`libc::IPPROTO_TCP`),
++///    and more. Please refer to your system manual for more options. Will be passed as the second
++///    argument (`level`) to the `getsockopt`/`setsockopt` call.
++/// * `$flag:path`: a flag name to set. Some examples: `libc::SO_REUSEADDR`, `libc::TCP_NODELAY`,
++///    `libc::IP_ADD_MEMBERSHIP` and others. Will be passed as the third argument (`option_name`)
++///    to the `setsockopt`/`getsockopt` call.
++/// * `$ty:ty`: type of the value that will be get/set.
++/// * `$getter:ty`: `Get` implementation; optional; only for `GetOnly` and `Both`.
++/// * `$setter:ty`: `Set` implementation; optional; only for `SetOnly` and `Both`.
++macro_rules! sockopt_impl {
++    (GetOnly, $name:ident, $level:path, $flag:path, bool) => {
++        sockopt_impl!(GetOnly, $name, $level, $flag, bool, GetBool);
++    };
++
++    (GetOnly, $name:ident, $level:path, $flag:path, u8) => {
++        sockopt_impl!(GetOnly, $name, $level, $flag, u8, GetU8);
++    };
++
++    (GetOnly, $name:ident, $level:path, $flag:path, usize) => {
++        sockopt_impl!(GetOnly, $name, $level, $flag, usize, GetUsize);
++    };
++
++    (SetOnly, $name:ident, $level:path, $flag:path, bool) => {
++        sockopt_impl!(SetOnly, $name, $level, $flag, bool, SetBool);
++    };
++
++    (SetOnly, $name:ident, $level:path, $flag:path, u8) => {
++        sockopt_impl!(SetOnly, $name, $level, $flag, u8, SetU8);
++    };
++
++    (SetOnly, $name:ident, $level:path, $flag:path, usize) => {
++        sockopt_impl!(SetOnly, $name, $level, $flag, usize, SetUsize);
++    };
++
++    (Both, $name:ident, $level:path, $flag:path, bool) => {
++        sockopt_impl!(Both, $name, $level, $flag, bool, GetBool, SetBool);
++    };
++
++    (Both, $name:ident, $level:path, $flag:path, u8) => {
++        sockopt_impl!(Both, $name, $level, $flag, u8, GetU8, SetU8);
++    };
++
++    (Both, $name:ident, $level:path, $flag:path, usize) => {
++        sockopt_impl!(Both, $name, $level, $flag, usize, GetUsize, SetUsize);
++    };
++
++    (Both, $name:ident, $level:path, $flag:path, OsString<$array:ty>) => {
++        sockopt_impl!(Both, $name, $level, $flag, OsString, GetOsString<$array>, SetOsString);
++    };
++
++    /*
++     * Matchers with generic getter types must be placed at the end, so
++     * they'll only match _after_ specialized matchers fail
++     */
++    (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
++        sockopt_impl!(GetOnly, $name, $level, $flag, $ty, GetStruct<$ty>);
++    };
++
++    (GetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty) => {
++        #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++        pub struct $name;
++
++        getsockopt_impl!($name, $level, $flag, $ty, $getter);
++    };
++
++    (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty) => {
++        sockopt_impl!(SetOnly, $name, $level, $flag, $ty, SetStruct<$ty>);
++    };
++
++    (SetOnly, $name:ident, $level:path, $flag:path, $ty:ty, $setter:ty) => {
++        #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++        pub struct $name;
++
++        setsockopt_impl!($name, $level, $flag, $ty, $setter);
++    };
++
++    (Both, $name:ident, $level:path, $flag:path, $ty:ty, $getter:ty, $setter:ty) => {
++        #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++        pub struct $name;
++
++        setsockopt_impl!($name, $level, $flag, $ty, $setter);
++        getsockopt_impl!($name, $level, $flag, $ty, $getter);
++    };
++
++    (Both, $name:ident, $level:path, $flag:path, $ty:ty) => {
++        sockopt_impl!(Both, $name, $level, $flag, $ty, GetStruct<$ty>, SetStruct<$ty>);
++    };
++}
++
++/*
++ *
++ * ===== Define sockopts =====
++ *
++ */
++
++sockopt_impl!(Both, ReuseAddr, libc::SOL_SOCKET, libc::SO_REUSEADDR, bool);
++sockopt_impl!(Both, ReusePort, libc::SOL_SOCKET, libc::SO_REUSEPORT, bool);
++sockopt_impl!(Both, TcpNoDelay, libc::IPPROTO_TCP, libc::TCP_NODELAY, bool);
++sockopt_impl!(Both, Linger, libc::SOL_SOCKET, libc::SO_LINGER, libc::linger);
++sockopt_impl!(SetOnly, IpAddMembership, libc::IPPROTO_IP, libc::IP_ADD_MEMBERSHIP, super::IpMembershipRequest);
++sockopt_impl!(SetOnly, IpDropMembership, libc::IPPROTO_IP, libc::IP_DROP_MEMBERSHIP, super::IpMembershipRequest);
++cfg_if! {
++    if #[cfg(any(target_os = "android", target_os = "linux"))] {
++        sockopt_impl!(SetOnly, Ipv6AddMembership, libc::IPPROTO_IPV6, libc::IPV6_ADD_MEMBERSHIP, super::Ipv6MembershipRequest);
++        sockopt_impl!(SetOnly, Ipv6DropMembership, libc::IPPROTO_IPV6, libc::IPV6_DROP_MEMBERSHIP, super::Ipv6MembershipRequest);
++    } else if #[cfg(any(target_os = "dragonfly",
++                        target_os = "freebsd",
++                        target_os = "ios",
++                        target_os = "macos",
++                        target_os = "netbsd",
++                        target_os = "openbsd"))] {
++        sockopt_impl!(SetOnly, Ipv6AddMembership, libc::IPPROTO_IPV6, libc::IPV6_JOIN_GROUP, super::Ipv6MembershipRequest);
++        sockopt_impl!(SetOnly, Ipv6DropMembership, libc::IPPROTO_IPV6, libc::IPV6_LEAVE_GROUP, super::Ipv6MembershipRequest);
++    }
++}
++sockopt_impl!(Both, IpMulticastTtl, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, u8);
++sockopt_impl!(Both, IpMulticastLoop, libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, bool);
++sockopt_impl!(Both, ReceiveTimeout, libc::SOL_SOCKET, libc::SO_RCVTIMEO, TimeVal);
++sockopt_impl!(Both, SendTimeout, libc::SOL_SOCKET, libc::SO_SNDTIMEO, TimeVal);
++sockopt_impl!(Both, Broadcast, libc::SOL_SOCKET, libc::SO_BROADCAST, bool);
++sockopt_impl!(Both, OobInline, libc::SOL_SOCKET, libc::SO_OOBINLINE, bool);
++sockopt_impl!(GetOnly, SocketError, libc::SOL_SOCKET, libc::SO_ERROR, i32);
++sockopt_impl!(Both, KeepAlive, libc::SOL_SOCKET, libc::SO_KEEPALIVE, bool);
++#[cfg(any(target_os = "android", target_os = "linux"))]
++sockopt_impl!(GetOnly, PeerCredentials, libc::SOL_SOCKET, libc::SO_PEERCRED, super::UnixCredentials);
++#[cfg(any(target_os = "ios",
++          target_os = "macos"))]
++sockopt_impl!(Both, TcpKeepAlive, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, u32);
++#[cfg(any(target_os = "android",
++          target_os = "dragonfly",
++          target_os = "freebsd",
++          target_os = "linux",
++          target_os = "nacl"))]
++sockopt_impl!(Both, TcpKeepIdle, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, u32);
++sockopt_impl!(Both, RcvBuf, libc::SOL_SOCKET, libc::SO_RCVBUF, usize);
++sockopt_impl!(Both, SndBuf, libc::SOL_SOCKET, libc::SO_SNDBUF, usize);
++#[cfg(any(target_os = "android", target_os = "linux"))]
++sockopt_impl!(SetOnly, RcvBufForce, libc::SOL_SOCKET, libc::SO_RCVBUFFORCE, usize);
++#[cfg(any(target_os = "android", target_os = "linux"))]
++sockopt_impl!(SetOnly, SndBufForce, libc::SOL_SOCKET, libc::SO_SNDBUFFORCE, usize);
++sockopt_impl!(GetOnly, SockType, libc::SOL_SOCKET, libc::SO_TYPE, super::SockType);
++sockopt_impl!(GetOnly, AcceptConn, libc::SOL_SOCKET, libc::SO_ACCEPTCONN, bool);
++#[cfg(any(target_os = "android", target_os = "linux"))]
++sockopt_impl!(GetOnly, OriginalDst, libc::SOL_IP, libc::SO_ORIGINAL_DST, libc::sockaddr_in);
++sockopt_impl!(Both, ReceiveTimestamp, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool);
++#[cfg(any(target_os = "android", target_os = "linux"))]
++sockopt_impl!(Both, IpTransparent, libc::SOL_IP, libc::IP_TRANSPARENT, bool);
++#[cfg(target_os = "openbsd")]
++sockopt_impl!(Both, BindAny, libc::SOL_SOCKET, libc::SO_BINDANY, bool);
++#[cfg(target_os = "freebsd")]
++sockopt_impl!(Both, BindAny, libc::IPPROTO_IP, libc::IP_BINDANY, bool);
++#[cfg(target_os = "linux")]
++sockopt_impl!(Both, Mark, libc::SOL_SOCKET, libc::SO_MARK, u32);
++#[cfg(any(target_os = "android", target_os = "linux"))]
++sockopt_impl!(Both, PassCred, libc::SOL_SOCKET, libc::SO_PASSCRED, bool);
++#[cfg(any(target_os = "freebsd", target_os = "linux"))] 
++sockopt_impl!(Both, TcpCongestion, libc::IPPROTO_TCP, libc::TCP_CONGESTION, OsString<[u8; TCP_CA_NAME_MAX]>);
++#[cfg(any(
++    target_os = "android",
++    target_os = "ios",
++    target_os = "linux",
++    target_os = "macos",
++    target_os = "netbsd",
++))]
++sockopt_impl!(Both, Ipv4PacketInfo, libc::IPPROTO_IP, libc::IP_PKTINFO, bool);
++#[cfg(any(
++    target_os = "android",
++    target_os = "freebsd",
++    target_os = "ios",
++    target_os = "linux",
++    target_os = "macos",
++    target_os = "netbsd",
++    target_os = "openbsd",
++))]
++sockopt_impl!(Both, Ipv6RecvPacketInfo, libc::IPPROTO_IPV6, libc::IPV6_RECVPKTINFO, bool);
++#[cfg(any(
++    target_os = "freebsd",
++    target_os = "ios",
++    target_os = "macos",
++    target_os = "netbsd",
++    target_os = "openbsd",
++))]
++sockopt_impl!(Both, Ipv4RecvIf, libc::IPPROTO_IP, libc::IP_RECVIF, bool);
++#[cfg(any(
++    target_os = "freebsd",
++    target_os = "ios",
++    target_os = "macos",
++    target_os = "netbsd",
++    target_os = "openbsd",
++))]
++sockopt_impl!(Both, Ipv4RecvDstAddr, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, bool);
++
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++#[derive(Copy, Clone, Debug)]
++pub struct AlgSetAeadAuthSize;
++
++// ALG_SET_AEAD_AUTH_SIZE read the length from passed `option_len`
++// See https://elixir.bootlin.com/linux/v4.4/source/crypto/af_alg.c#L222
++#[cfg(any(target_os = "android", target_os = "linux"))]
++impl SetSockOpt for AlgSetAeadAuthSize {
++    type Val = usize;
++
++    fn set(&self, fd: RawFd, val: &usize) -> Result<()> {
++        unsafe {
++            let res = libc::setsockopt(fd,
++                                       libc::SOL_ALG,
++                                       libc::ALG_SET_AEAD_AUTHSIZE,
++                                       ::std::ptr::null(),
++                                       *val as libc::socklen_t);
++            Errno::result(res).map(drop)
++        }
++    }
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++#[derive(Clone, Debug)]
++pub struct AlgSetKey<T>(::std::marker::PhantomData<T>);
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++impl<T> Default for AlgSetKey<T> {
++    fn default() -> Self {
++        AlgSetKey(Default::default())
++    }
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++impl<T> SetSockOpt for AlgSetKey<T> where T: AsRef<[u8]> + Clone {
++    type Val = T;
++
++    fn set(&self, fd: RawFd, val: &T) -> Result<()> {
++        unsafe {
++            let res = libc::setsockopt(fd,
++                                       libc::SOL_ALG,
++                                       libc::ALG_SET_KEY,
++                                       val.as_ref().as_ptr() as *const _,
++                                       val.as_ref().len() as libc::socklen_t);
++            Errno::result(res).map(drop)
++        }
++    }
++}
++
++/*
++ *
++ * ===== Accessor helpers =====
++ *
++ */
++
++/// Helper trait that describes what is expected from a `GetSockOpt` getter.
++unsafe trait Get<T> {
++    /// Returns an empty value.
++    unsafe fn blank() -> Self;
++    /// Returns a pointer to the stored value. This pointer will be passed to the system's
++    /// `getsockopt` call (`man 3p getsockopt`, argument `option_value`).
++    fn ffi_ptr(&mut self) -> *mut c_void;
++    /// Returns length of the stored value. This pointer will be passed to the system's
++    /// `getsockopt` call (`man 3p getsockopt`, argument `option_len`).
++    fn ffi_len(&mut self) -> *mut socklen_t;
++    /// Returns the stored value.
++    unsafe fn unwrap(self) -> T;
++}
++
++/// Helper trait that describes what is expected from a `SetSockOpt` setter.
++unsafe trait Set<'a, T> {
++    /// Initialize the setter with a given value.
++    fn new(val: &'a T) -> Self;
++    /// Returns a pointer to the stored value. This pointer will be passed to the system's
++    /// `setsockopt` call (`man 3p setsockopt`, argument `option_value`).
++    fn ffi_ptr(&self) -> *const c_void;
++    /// Returns length of the stored value. This pointer will be passed to the system's
++    /// `setsockopt` call (`man 3p setsockopt`, argument `option_len`).
++    fn ffi_len(&self) -> socklen_t;
++}
++
++/// Getter for an arbitrary `struct`.
++struct GetStruct<T> {
++    len: socklen_t,
++    val: T,
++}
++
++unsafe impl<T> Get<T> for GetStruct<T> {
++    unsafe fn blank() -> Self {
++        GetStruct {
++            len: mem::size_of::<T>() as socklen_t,
++            val: mem::zeroed(),
++        }
++    }
++
++    fn ffi_ptr(&mut self) -> *mut c_void {
++        &mut self.val as *mut T as *mut c_void
++    }
++
++    fn ffi_len(&mut self) -> *mut socklen_t {
++        &mut self.len
++    }
++
++    unsafe fn unwrap(self) -> T {
++        assert!(self.len as usize == mem::size_of::<T>(), "invalid getsockopt implementation");
++        self.val
++    }
++}
++
++/// Setter for an arbitrary `struct`.
++struct SetStruct<'a, T: 'static> {
++    ptr: &'a T,
++}
++
++unsafe impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
++    fn new(ptr: &'a T) -> SetStruct<'a, T> {
++        SetStruct { ptr: ptr }
++    }
++
++    fn ffi_ptr(&self) -> *const c_void {
++        self.ptr as *const T as *const c_void
++    }
++
++    fn ffi_len(&self) -> socklen_t {
++        mem::size_of::<T>() as socklen_t
++    }
++}
++
++/// Getter for a boolean value.
++struct GetBool {
++    len: socklen_t,
++    val: c_int,
++}
++
++unsafe impl Get<bool> for GetBool {
++    unsafe fn blank() -> Self {
++        GetBool {
++            len: mem::size_of::<c_int>() as socklen_t,
++            val: mem::zeroed(),
++        }
++    }
++
++    fn ffi_ptr(&mut self) -> *mut c_void {
++        &mut self.val as *mut c_int as *mut c_void
++    }
++
++    fn ffi_len(&mut self) -> *mut socklen_t {
++        &mut self.len
++    }
++
++    unsafe fn unwrap(self) -> bool {
++        assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation");
++        self.val != 0
++    }
++}
++
++/// Setter for a boolean value.
++struct SetBool {
++    val: c_int,
++}
++
++unsafe impl<'a> Set<'a, bool> for SetBool {
++    fn new(val: &'a bool) -> SetBool {
++        SetBool { val: if *val { 1 } else { 0 } }
++    }
++
++    fn ffi_ptr(&self) -> *const c_void {
++        &self.val as *const c_int as *const c_void
++    }
++
++    fn ffi_len(&self) -> socklen_t {
++        mem::size_of::<c_int>() as socklen_t
++    }
++}
++
++/// Getter for an `u8` value.
++struct GetU8 {
++    len: socklen_t,
++    val: u8,
++}
++
++unsafe impl Get<u8> for GetU8 {
++    unsafe fn blank() -> Self {
++        GetU8 {
++            len: mem::size_of::<u8>() as socklen_t,
++            val: mem::zeroed(),
++        }
++    }
++
++    fn ffi_ptr(&mut self) -> *mut c_void {
++        &mut self.val as *mut u8 as *mut c_void
++    }
++
++    fn ffi_len(&mut self) -> *mut socklen_t {
++        &mut self.len
++    }
++
++    unsafe fn unwrap(self) -> u8 {
++        assert!(self.len as usize == mem::size_of::<u8>(), "invalid getsockopt implementation");
++        self.val as u8
++    }
++}
++
++/// Setter for an `u8` value.
++struct SetU8 {
++    val: u8,
++}
++
++unsafe impl<'a> Set<'a, u8> for SetU8 {
++    fn new(val: &'a u8) -> SetU8 {
++        SetU8 { val: *val as u8 }
++    }
++
++    fn ffi_ptr(&self) -> *const c_void {
++        &self.val as *const u8 as *const c_void
++    }
++
++    fn ffi_len(&self) -> socklen_t {
++        mem::size_of::<c_int>() as socklen_t
++    }
++}
++
++/// Getter for an `usize` value.
++struct GetUsize {
++    len: socklen_t,
++    val: c_int,
++}
++
++unsafe impl Get<usize> for GetUsize {
++    unsafe fn blank() -> Self {
++        GetUsize {
++            len: mem::size_of::<c_int>() as socklen_t,
++            val: mem::zeroed(),
++        }
++    }
++
++    fn ffi_ptr(&mut self) -> *mut c_void {
++        &mut self.val as *mut c_int as *mut c_void
++    }
++
++    fn ffi_len(&mut self) -> *mut socklen_t {
++        &mut self.len
++    }
++
++    unsafe fn unwrap(self) -> usize {
++        assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation");
++        self.val as usize
++    }
++}
++
++/// Setter for an `usize` value.
++struct SetUsize {
++    val: c_int,
++}
++
++unsafe impl<'a> Set<'a, usize> for SetUsize {
++    fn new(val: &'a usize) -> SetUsize {
++        SetUsize { val: *val as c_int }
++    }
++
++    fn ffi_ptr(&self) -> *const c_void {
++        &self.val as *const c_int as *const c_void
++    }
++
++    fn ffi_len(&self) -> socklen_t {
++        mem::size_of::<c_int>() as socklen_t
++    }
++}
++
++/// Getter for a `OsString` value.
++struct GetOsString<T: AsMut<[u8]>> {
++    len: socklen_t,
++    val: T,
++}
++
++unsafe impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
++    unsafe fn blank() -> Self {
++        GetOsString {
++            len: mem::size_of::<T>() as socklen_t,
++            val: mem::zeroed(),
++        }
++    }
++
++    fn ffi_ptr(&mut self) -> *mut c_void {
++        &mut self.val as *mut T as *mut c_void
++    }
++
++    fn ffi_len(&mut self) -> *mut socklen_t {
++        &mut self.len
++    }
++
++    unsafe fn unwrap(mut self) -> OsString {
++        OsStr::from_bytes(self.val.as_mut()).to_owned()
++    }
++}
++
++/// Setter for a `OsString` value.
++struct SetOsString<'a> {
++    val: &'a OsStr,
++}
++
++unsafe impl<'a> Set<'a, OsString> for SetOsString<'a> {
++    fn new(val: &'a OsString) -> SetOsString {
++        SetOsString { val: val.as_os_str() }
++    }
++
++    fn ffi_ptr(&self) -> *const c_void {
++        self.val.as_bytes().as_ptr() as *const c_void
++    }
++
++    fn ffi_len(&self) -> socklen_t {
++        self.val.len() as socklen_t
++    }
++}
++
++
++#[cfg(test)]
++mod test {
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    #[test]
++    fn can_get_peercred_on_unix_socket() {
++        use super::super::*;
++
++        let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
++        let a_cred = getsockopt(a, super::PeerCredentials).unwrap();
++        let b_cred = getsockopt(b, super::PeerCredentials).unwrap();
++        assert_eq!(a_cred, b_cred);
++        assert!(a_cred.pid() != 0);
++    }
++
++    #[test]
++    fn is_socket_type_unix() {
++        use super::super::*;
++        use ::unistd::close;
++
++        let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
++        let a_type = getsockopt(a, super::SockType).unwrap();
++        assert!(a_type == SockType::Stream);
++        close(a).unwrap();
++        close(b).unwrap();
++    }
++
++    #[test]
++    fn is_socket_type_dgram() {
++        use super::super::*;
++        use ::unistd::close;
++
++        let s = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap();
++        let s_type = getsockopt(s, super::SockType).unwrap();
++        assert!(s_type == SockType::Datagram);
++        close(s).unwrap();
++    }
++
++    #[cfg(any(target_os = "freebsd",
++              target_os = "linux",
++              target_os = "nacl"))]
++    #[test]
++    fn can_get_listen_on_tcp_socket() {
++        use super::super::*;
++        use ::unistd::close;
++
++        let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
++        let s_listening = getsockopt(s, super::AcceptConn).unwrap();
++        assert!(!s_listening);
++        listen(s, 10).unwrap();
++        let s_listening2 = getsockopt(s, super::AcceptConn).unwrap();
++        assert!(s_listening2);
++        close(s).unwrap();
++    }
++
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/stat.rs b/third_party/rust/nix-0.15.0/src/sys/stat.rs
+new file mode 100644
+index 0000000000000..66c8c9dd1b720
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/stat.rs
+@@ -0,0 +1,294 @@
++pub use libc::{dev_t, mode_t};
++pub use libc::stat as FileStat;
++
++use {Result, NixPath};
++use errno::Errno;
++use fcntl::{AtFlags, at_rawfd};
++use libc;
++use std::mem;
++use std::os::unix::io::RawFd;
++use sys::time::{TimeSpec, TimeVal};
++
++libc_bitflags!(
++    pub struct SFlag: mode_t {
++        S_IFIFO;
++        S_IFCHR;
++        S_IFDIR;
++        S_IFBLK;
++        S_IFREG;
++        S_IFLNK;
++        S_IFSOCK;
++        S_IFMT;
++    }
++);
++
++libc_bitflags! {
++    pub struct Mode: mode_t {
++        S_IRWXU;
++        S_IRUSR;
++        S_IWUSR;
++        S_IXUSR;
++        S_IRWXG;
++        S_IRGRP;
++        S_IWGRP;
++        S_IXGRP;
++        S_IRWXO;
++        S_IROTH;
++        S_IWOTH;
++        S_IXOTH;
++        S_ISUID as mode_t;
++        S_ISGID as mode_t;
++        S_ISVTX as mode_t;
++    }
++}
++
++pub fn mknod<P: ?Sized + NixPath>(path: &P, kind: SFlag, perm: Mode, dev: dev_t) -> Result<()> {
++    let res = path.with_nix_path(|cstr| {
++        unsafe {
++            libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev)
++        }
++    })?;
++
++    Errno::result(res).map(drop)
++}
++
++#[cfg(target_os = "linux")]
++pub fn major(dev: dev_t) -> u64 {
++    ((dev >> 32) & 0xffff_f000) |
++    ((dev >>  8) & 0x0000_0fff)
++}
++
++#[cfg(target_os = "linux")]
++pub fn minor(dev: dev_t) -> u64 {
++    ((dev >> 12) & 0xffff_ff00) |
++    ((dev      ) & 0x0000_00ff)
++}
++
++#[cfg(target_os = "linux")]
++pub fn makedev(major: u64, minor: u64) -> dev_t {
++    ((major & 0xffff_f000) << 32) |
++    ((major & 0x0000_0fff) <<  8) |
++    ((minor & 0xffff_ff00) << 12) |
++     (minor & 0x0000_00ff)
++}
++
++pub fn umask(mode: Mode) -> Mode {
++    let prev = unsafe { libc::umask(mode.bits() as mode_t) };
++    Mode::from_bits(prev).expect("[BUG] umask returned invalid Mode")
++}
++
++pub fn stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
++    let mut dst = unsafe { mem::uninitialized() };
++    let res = path.with_nix_path(|cstr| {
++        unsafe {
++            libc::stat(cstr.as_ptr(), &mut dst as *mut FileStat)
++        }
++    })?;
++
++    Errno::result(res)?;
++
++    Ok(dst)
++}
++
++pub fn lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
++    let mut dst = unsafe { mem::uninitialized() };
++    let res = path.with_nix_path(|cstr| {
++        unsafe {
++            libc::lstat(cstr.as_ptr(), &mut dst as *mut FileStat)
++        }
++    })?;
++
++    Errno::result(res)?;
++
++    Ok(dst)
++}
++
++pub fn fstat(fd: RawFd) -> Result<FileStat> {
++    let mut dst = unsafe { mem::uninitialized() };
++    let res = unsafe { libc::fstat(fd, &mut dst as *mut FileStat) };
++
++    Errno::result(res)?;
++
++    Ok(dst)
++}
++
++pub fn fstatat<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, f: AtFlags) -> Result<FileStat> {
++    let mut dst = unsafe { mem::uninitialized() };
++    let res = pathname.with_nix_path(|cstr| {
++        unsafe { libc::fstatat(dirfd, cstr.as_ptr(), &mut dst as *mut FileStat, f.bits() as libc::c_int) }
++    })?;
++
++    Errno::result(res)?;
++
++    Ok(dst)
++}
++
++/// Change the file permission bits of the file specified by a file descriptor.
++///
++/// # References
++///
++/// [fchmod(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmod.html).
++pub fn fchmod(fd: RawFd, mode: Mode) -> Result<()> {
++    let res = unsafe { libc::fchmod(fd, mode.bits() as mode_t) };
++
++    Errno::result(res).map(drop)
++}
++
++/// Flags for `fchmodat` function.
++#[derive(Clone, Copy, Debug)]
++pub enum FchmodatFlags {
++    FollowSymlink,
++    NoFollowSymlink,
++}
++
++/// Change the file permission bits.
++///
++/// The file to be changed is determined relative to the directory associated
++/// with the file descriptor `dirfd` or the current working directory
++/// if `dirfd` is `None`.
++///
++/// If `flag` is `FchmodatFlags::NoFollowSymlink` and `path` names a symbolic link,
++/// then the mode of the symbolic link is changed.
++///
++/// `fchmod(None, path, mode, FchmodatFlags::FollowSymlink)` is identical to
++/// a call `libc::chmod(path, mode)`. That's why `chmod` is unimplemented
++/// in the `nix` crate.
++///
++/// # References
++///
++/// [fchmodat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html).
++pub fn fchmodat<P: ?Sized + NixPath>(
++    dirfd: Option<RawFd>,
++    path: &P,
++    mode: Mode,
++    flag: FchmodatFlags,
++) -> Result<()> {
++    let atflag =
++        match flag {
++            FchmodatFlags::FollowSymlink => AtFlags::empty(),
++            FchmodatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
++        };
++    let res = path.with_nix_path(|cstr| unsafe {
++        libc::fchmodat(
++            at_rawfd(dirfd),
++            cstr.as_ptr(),
++            mode.bits() as mode_t,
++            atflag.bits() as libc::c_int,
++        )
++    })?;
++
++    Errno::result(res).map(drop)
++}
++
++/// Change the access and modification times of a file.
++///
++/// `utimes(path, times)` is identical to
++/// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)`. The former
++/// is a deprecated API so prefer using the latter if the platforms you care
++/// about support it.
++///
++/// # References
++///
++/// [utimes(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/utimes.html).
++pub fn utimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> {
++    let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
++    let res = path.with_nix_path(|cstr| unsafe {
++        libc::utimes(cstr.as_ptr(), &times[0])
++    })?;
++
++    Errno::result(res).map(drop)
++}
++
++/// Change the access and modification times of a file without following symlinks.
++///
++/// `lutimes(path, times)` is identical to
++/// `utimensat(None, path, times, UtimensatFlags::NoFollowSymlink)`. The former
++/// is a deprecated API so prefer using the latter if the platforms you care
++/// about support it.
++///
++/// # References
++///
++/// [lutimes(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lutimes.html).
++#[cfg(any(target_os = "linux",
++          target_os = "haiku",
++          target_os = "ios",
++          target_os = "macos",
++          target_os = "freebsd",
++          target_os = "netbsd"))]
++pub fn lutimes<P: ?Sized + NixPath>(path: &P, atime: &TimeVal, mtime: &TimeVal) -> Result<()> {
++    let times: [libc::timeval; 2] = [*atime.as_ref(), *mtime.as_ref()];
++    let res = path.with_nix_path(|cstr| unsafe {
++        libc::lutimes(cstr.as_ptr(), &times[0])
++    })?;
++
++    Errno::result(res).map(drop)
++}
++
++/// Change the access and modification times of the file specified by a file descriptor.
++///
++/// # References
++///
++/// [futimens(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/futimens.html).
++#[inline]
++pub fn futimens(fd: RawFd, atime: &TimeSpec, mtime: &TimeSpec) -> Result<()> {
++    let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
++    let res = unsafe { libc::futimens(fd, &times[0]) };
++
++    Errno::result(res).map(drop)
++}
++
++/// Flags for `utimensat` function.
++#[derive(Clone, Copy, Debug)]
++pub enum UtimensatFlags {
++    FollowSymlink,
++    NoFollowSymlink,
++}
++
++/// Change the access and modification times of a file.
++///
++/// The file to be changed is determined relative to the directory associated
++/// with the file descriptor `dirfd` or the current working directory
++/// if `dirfd` is `None`.
++///
++/// If `flag` is `UtimensatFlags::NoFollowSymlink` and `path` names a symbolic link,
++/// then the mode of the symbolic link is changed.
++///
++/// `utimensat(None, path, times, UtimensatFlags::FollowSymlink)` is identical to
++/// `utimes(path, times)`. The latter is a deprecated API so prefer using the
++/// former if the platforms you care about support it.
++///
++/// # References
++///
++/// [utimensat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html).
++pub fn utimensat<P: ?Sized + NixPath>(
++    dirfd: Option<RawFd>,
++    path: &P,
++    atime: &TimeSpec,
++    mtime: &TimeSpec,
++    flag: UtimensatFlags
++) -> Result<()> {
++    let atflag =
++        match flag {
++            UtimensatFlags::FollowSymlink => AtFlags::empty(),
++            UtimensatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
++        };
++    let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
++    let res = path.with_nix_path(|cstr| unsafe {
++        libc::utimensat(
++            at_rawfd(dirfd),
++            cstr.as_ptr(),
++            &times[0],
++            atflag.bits() as libc::c_int,
++        )
++    })?;
++
++    Errno::result(res).map(drop)
++}
++
++pub fn mkdirat<P: ?Sized + NixPath>(fd: RawFd, path: &P, mode: Mode) -> Result<()> {
++    let res = path.with_nix_path(|cstr| {
++        unsafe { libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) }
++    })?;
++
++    Errno::result(res).map(drop)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/statfs.rs b/third_party/rust/nix-0.15.0/src/sys/statfs.rs
+new file mode 100644
+index 0000000000000..d4596bf336958
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/statfs.rs
+@@ -0,0 +1,548 @@
++use std::fmt::{self, Debug};
++use std::mem;
++use std::os::unix::io::AsRawFd;
++#[cfg(not(any(target_os = "linux", target_os = "android")))]
++use std::ffi::CStr;
++
++use libc;
++
++use {NixPath, Result};
++use errno::Errno;
++
++#[cfg(target_os = "android")]
++pub type fsid_t = libc::__fsid_t;
++#[cfg(not(target_os = "android"))]
++pub type fsid_t = libc::fsid_t;
++
++#[derive(Clone, Copy)]
++pub struct Statfs(libc::statfs);
++
++#[cfg(target_os = "freebsd")]
++#[derive(Eq, Copy, Clone, PartialEq, Debug)]
++pub struct FsType(u32);
++#[cfg(target_os = "android")]
++#[derive(Eq, Copy, Clone, PartialEq, Debug)]
++pub struct FsType(libc::c_ulong);
++#[cfg(all(target_os = "linux", target_arch = "s390x"))]
++#[derive(Eq, Copy, Clone, PartialEq, Debug)]
++pub struct FsType(u32);
++#[cfg(all(target_os = "linux", target_env = "musl"))]
++#[derive(Eq, Copy, Clone, PartialEq, Debug)]
++pub struct FsType(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(libc::c_long);
++
++#[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 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);
++
++impl Statfs {
++    /// Magic code defining system type
++    #[cfg(not(any(
++        target_os = "openbsd",
++        target_os = "ios",
++        target_os = "macos"
++    )))]
++    pub fn filesystem_type(&self) -> FsType {
++        FsType(self.0.f_type)
++    }
++
++    /// Magic code defining system type
++    #[cfg(not(any(target_os = "linux", target_os = "android")))]
++    pub fn filesystem_type_name(&self) -> &str {
++        let c_str = unsafe { CStr::from_ptr(self.0.f_fstypename.as_ptr()) };
++        c_str.to_str().unwrap()
++    }
++
++    /// Optimal transfer block size
++    #[cfg(any(target_os = "ios", target_os = "macos", target_os = "openbsd"))]
++    pub fn optimal_transfer_size(&self) -> i32 {
++        self.0.f_iosize
++    }
++
++    /// Optimal transfer block size
++    #[cfg(all(target_os = "linux", target_arch = "s390x"))]
++    pub fn optimal_transfer_size(&self) -> u32 {
++        self.0.f_bsize
++    }
++
++    /// Optimal transfer block size
++    #[cfg(all(target_os = "linux", target_env = "musl"))]
++    pub fn optimal_transfer_size(&self) -> libc::c_ulong {
++        self.0.f_bsize
++    }
++
++    /// 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 {
++        self.0.f_bsize
++    }
++
++    /// Optimal transfer block size
++    #[cfg(target_os = "android")]
++    pub fn optimal_transfer_size(&self) -> libc::c_ulong {
++        self.0.f_bsize
++    }
++
++    /// Optimal transfer block size
++    #[cfg(target_os = "dragonfly")]
++    pub fn optimal_transfer_size(&self) -> libc::c_long {
++        self.0.f_iosize
++    }
++
++    /// Optimal transfer block size
++    #[cfg(target_os = "freebsd")]
++    pub fn optimal_transfer_size(&self) -> u64 {
++        self.0.f_iosize
++    }
++
++    /// Size of a block
++    #[cfg(any(target_os = "ios", target_os = "macos", target_os = "openbsd"))]
++    pub fn block_size(&self) -> u32 {
++        self.0.f_bsize
++    }
++
++    /// 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", target_arch = "s390x"))]
++    pub fn block_size(&self) -> u32 {
++        self.0.f_bsize
++    }
++
++    /// 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", target_env = "musl"))]
++    pub fn block_size(&self) -> libc::c_ulong {
++        self.0.f_bsize
++    }
++
++    /// 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 {
++        self.0.f_bsize
++    }
++
++    /// Size of a block
++    #[cfg(target_os = "freebsd")]
++    pub fn block_size(&self) -> u64 {
++        self.0.f_bsize
++    }
++
++    /// Size of a block
++    #[cfg(target_os = "android")]
++    pub fn block_size(&self) -> libc::c_ulong {
++        self.0.f_bsize
++    }
++
++    /// Size of a block
++    #[cfg(target_os = "dragonfly")]
++    pub fn block_size(&self) -> libc::c_long {
++        self.0.f_bsize
++    }
++
++    /// Maximum length of filenames
++    #[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
++    pub fn maximum_name_length(&self) -> u32 {
++        self.0.f_namemax
++    }
++
++    /// Maximum length of filenames
++    #[cfg(all(target_os = "linux", target_arch = "s390x"))]
++    pub fn maximum_name_length(&self) -> u32 {
++        self.0.f_namelen
++    }
++
++    /// Maximum length of filenames
++    #[cfg(all(target_os = "linux", target_env = "musl"))]
++    pub fn maximum_name_length(&self) -> libc::c_ulong {
++        self.0.f_namelen
++    }
++
++    /// 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 {
++        self.0.f_namelen
++    }
++
++    /// Maximum length of filenames
++    #[cfg(target_os = "android")]
++    pub fn maximum_name_length(&self) -> libc::c_ulong {
++        self.0.f_namelen
++    }
++
++    /// Total data blocks in filesystem
++    #[cfg(any(
++        target_os = "ios",
++        target_os = "macos",
++        target_os = "android",
++        target_os = "freebsd",
++        target_os = "openbsd",
++    ))]
++    pub fn blocks(&self) -> u64 {
++        self.0.f_blocks
++    }
++
++    /// Total data blocks in filesystem
++    #[cfg(target_os = "dragonfly")]
++    pub fn blocks(&self) -> libc::c_long {
++        self.0.f_blocks
++    }
++
++    /// Total data blocks in filesystem
++    #[cfg(all(target_os = "linux", target_env = "musl"))]
++    pub fn blocks(&self) -> u64 {
++        self.0.f_blocks
++    }
++
++    /// Total data blocks in filesystem
++    #[cfg(not(any(
++        target_os = "ios",
++        target_os = "macos",
++        target_os = "android",
++        target_os = "freebsd",
++        target_os = "openbsd",
++        target_os = "dragonfly",
++        all(target_os = "linux", target_env = "musl")
++    )))]
++    pub fn blocks(&self) -> libc::c_ulong {
++        self.0.f_blocks
++    }
++
++    /// Free blocks in filesystem
++    #[cfg(any(
++        target_os = "ios",
++        target_os = "macos",
++        target_os = "android",
++        target_os = "freebsd",
++        target_os = "openbsd",
++    ))]
++    pub fn blocks_free(&self) -> u64 {
++        self.0.f_bfree
++    }
++
++    /// Free blocks in filesystem
++    #[cfg(target_os = "dragonfly")]
++    pub fn blocks_free(&self) -> libc::c_long {
++        self.0.f_bfree
++    }
++
++    /// Free blocks in filesystem
++    #[cfg(all(target_os = "linux", target_env = "musl"))]
++    pub fn blocks_free(&self) -> u64 {
++        self.0.f_bfree
++    }
++
++    /// Free blocks in filesystem
++    #[cfg(not(any(
++        target_os = "ios",
++        target_os = "macos",
++        target_os = "android",
++        target_os = "freebsd",
++        target_os = "openbsd",
++        target_os = "dragonfly",
++        all(target_os = "linux", target_env = "musl")
++    )))]
++    pub fn blocks_free(&self) -> libc::c_ulong {
++        self.0.f_bfree
++    }
++
++    /// Free blocks available to unprivileged user
++    #[cfg(any(target_os = "ios", target_os = "macos", target_os = "android"))]
++    pub fn blocks_available(&self) -> u64 {
++        self.0.f_bavail
++    }
++
++    /// Free blocks available to unprivileged user
++    #[cfg(target_os = "dragonfly")]
++    pub fn blocks_available(&self) -> libc::c_long {
++        self.0.f_bavail
++    }
++
++    /// Free blocks available to unprivileged user
++    #[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
++    pub fn blocks_available(&self) -> i64 {
++        self.0.f_bavail
++    }
++
++    /// Free blocks available to unprivileged user
++    #[cfg(all(target_os = "linux", target_env = "musl"))]
++    pub fn blocks_available(&self) -> u64 {
++        self.0.f_bavail
++    }
++
++    /// Free blocks available to unprivileged user
++    #[cfg(not(any(
++        target_os = "ios",
++        target_os = "macos",
++        target_os = "android",
++        target_os = "freebsd",
++        target_os = "openbsd",
++        target_os = "dragonfly",
++        all(target_os = "linux", target_env = "musl")
++    )))]
++    pub fn blocks_available(&self) -> libc::c_ulong {
++        self.0.f_bavail
++    }
++
++    /// Total file nodes in filesystem
++    #[cfg(any(
++        target_os = "ios",
++        target_os = "macos",
++        target_os = "android",
++        target_os = "freebsd",
++        target_os = "openbsd",
++    ))]
++    pub fn files(&self) -> u64 {
++        self.0.f_files
++    }
++
++    /// Total file nodes in filesystem
++    #[cfg(target_os = "dragonfly")]
++    pub fn files(&self) -> libc::c_long {
++        self.0.f_files
++    }
++
++    /// Total file nodes in filesystem
++    #[cfg(all(target_os = "linux", target_env = "musl"))]
++    pub fn files(&self) -> u64 {
++        self.0.f_files
++    }
++
++    /// Total file nodes in filesystem
++    #[cfg(not(any(
++        target_os = "ios",
++        target_os = "macos",
++        target_os = "android",
++        target_os = "freebsd",
++        target_os = "openbsd",
++        target_os = "dragonfly",
++        all(target_os = "linux", target_env = "musl")
++    )))]
++    pub fn files(&self) -> libc::c_ulong {
++        self.0.f_files
++    }
++
++    /// Free file nodes in filesystem
++    #[cfg(any(target_os = "ios", target_os = "macos", target_os = "android"))]
++    pub fn files_free(&self) -> u64 {
++        self.0.f_ffree
++    }
++
++    /// Free file nodes in filesystem
++    #[cfg(target_os = "dragonfly")]
++    pub fn files_free(&self) -> libc::c_long {
++        self.0.f_ffree
++    }
++
++    /// Free file nodes in filesystem
++    #[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
++    pub fn files_free(&self) -> i64 {
++        self.0.f_ffree
++    }
++
++    /// Free file nodes in filesystem
++    #[cfg(all(target_os = "linux", target_env = "musl"))]
++    pub fn files_free(&self) -> u64 {
++        self.0.f_ffree
++    }
++
++    /// Free file nodes in filesystem
++    #[cfg(not(any(
++        target_os = "ios",
++        target_os = "macos",
++        target_os = "android",
++        target_os = "freebsd",
++        target_os = "openbsd",
++        target_os = "dragonfly",
++        all(target_os = "linux", target_env = "musl")
++    )))]
++    pub fn files_free(&self) -> libc::c_ulong {
++        self.0.f_ffree
++    }
++
++    /// Filesystem ID
++    pub fn filesystem_id(&self) -> fsid_t {
++        self.0.f_fsid
++    }
++}
++
++impl Debug for Statfs {
++    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++        f.debug_struct("Statfs")
++            .field("optimal_transfer_size", &self.optimal_transfer_size())
++            .field("block_size", &self.block_size())
++            .field("blocks", &self.blocks())
++            .field("blocks_free", &self.blocks_free())
++            .field("blocks_available", &self.blocks_available())
++            .field("files", &self.files())
++            .field("files_free", &self.files_free())
++            .field("filesystem_id", &self.filesystem_id())
++            .finish()
++    }
++}
++
++pub fn statfs<P: ?Sized + NixPath>(path: &P) -> Result<Statfs> {
++    unsafe {
++        let mut stat: Statfs = mem::uninitialized();
++        let res = path.with_nix_path(|path| libc::statfs(path.as_ptr(), &mut stat.0))?;
++        Errno::result(res).map(|_| stat)
++    }
++}
++
++pub fn fstatfs<T: AsRawFd>(fd: &T) -> Result<Statfs> {
++    unsafe {
++        let mut stat: Statfs = mem::uninitialized();
++        Errno::result(libc::fstatfs(fd.as_raw_fd(), &mut stat.0)).map(|_| stat)
++    }
++}
++
++#[cfg(test)]
++mod test {
++    use std::fs::File;
++
++    use sys::statfs::*;
++    use sys::statvfs::*;
++    use std::path::Path;
++
++    #[test]
++    fn statfs_call() {
++        check_statfs("/tmp");
++        check_statfs("/dev");
++        check_statfs("/run");
++        check_statfs("/");
++    }
++
++    #[test]
++    fn fstatfs_call() {
++        check_fstatfs("/tmp");
++        check_fstatfs("/dev");
++        check_fstatfs("/run");
++        check_fstatfs("/");
++    }
++
++    fn check_fstatfs(path: &str) {
++        if !Path::new(path).exists() {
++            return;
++        }
++        let vfs = statvfs(path.as_bytes()).unwrap();
++        let file = File::open(path).unwrap();
++        let fs = fstatfs(&file).unwrap();
++        assert_fs_equals(fs, vfs);
++    }
++
++    fn check_statfs(path: &str) {
++        if !Path::new(path).exists() {
++            return;
++        }
++        let vfs = statvfs(path.as_bytes()).unwrap();
++        let fs = statfs(path.as_bytes()).unwrap();
++        assert_fs_equals(fs, vfs);
++    }
++
++    fn assert_fs_equals(fs: Statfs, vfs: Statvfs) {
++        assert_eq!(fs.files() as u64, vfs.files() as u64);
++        assert_eq!(fs.blocks() as u64, vfs.blocks() as u64);
++        assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64);
++    }
++
++    // This test is ignored because files_free/blocks_free can change after statvfs call and before
++    // statfs call.
++    #[test]
++    #[ignore]
++    fn statfs_call_strict() {
++        check_statfs_strict("/tmp");
++        check_statfs_strict("/dev");
++        check_statfs_strict("/run");
++        check_statfs_strict("/");
++    }
++
++    // This test is ignored because files_free/blocks_free can change after statvfs call and before
++    // fstatfs call.
++    #[test]
++    #[ignore]
++    fn fstatfs_call_strict() {
++        check_fstatfs_strict("/tmp");
++        check_fstatfs_strict("/dev");
++        check_fstatfs_strict("/run");
++        check_fstatfs_strict("/");
++    }
++
++    fn check_fstatfs_strict(path: &str) {
++        if !Path::new(path).exists() {
++            return;
++        }
++        let vfs = statvfs(path.as_bytes());
++        let file = File::open(path).unwrap();
++        let fs = fstatfs(&file);
++        assert_fs_equals_strict(fs.unwrap(), vfs.unwrap())
++    }
++
++    fn check_statfs_strict(path: &str) {
++        if !Path::new(path).exists() {
++            return;
++        }
++        let vfs = statvfs(path.as_bytes());
++        let fs = statfs(path.as_bytes());
++        assert_fs_equals_strict(fs.unwrap(), vfs.unwrap())
++    }
++
++    fn assert_fs_equals_strict(fs: Statfs, vfs: Statvfs) {
++        assert_eq!(fs.files_free() as u64, vfs.files_free() as u64);
++        assert_eq!(fs.blocks_free() as u64, vfs.blocks_free() as u64);
++        assert_eq!(fs.blocks_available() as u64, vfs.blocks_available() as u64);
++        assert_eq!(fs.files() as u64, vfs.files() as u64);
++        assert_eq!(fs.blocks() as u64, vfs.blocks() as u64);
++        assert_eq!(fs.block_size() as u64, vfs.fragment_size() as u64);
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/statvfs.rs b/third_party/rust/nix-0.15.0/src/sys/statvfs.rs
+new file mode 100644
+index 0000000000000..e5980369d5119
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/statvfs.rs
+@@ -0,0 +1,160 @@
++//! Get filesystem statistics
++//!
++//! See [the man pages](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fstatvfs.html)
++//! for more details.
++use std::mem;
++use std::os::unix::io::AsRawFd;
++
++use libc::{self, c_ulong};
++
++use {Result, NixPath};
++use errno::Errno;
++
++libc_bitflags!(
++    /// File system mount Flags
++    #[repr(C)]
++    #[derive(Default)]
++    pub struct FsFlags: c_ulong {
++        /// Read Only
++        ST_RDONLY;
++        /// Do not allow the set-uid bits to have an effect
++        ST_NOSUID;
++        /// Do not interpret character or block-special devices
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        ST_NODEV;
++        /// Do not allow execution of binaries on the filesystem
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        ST_NOEXEC;
++        /// All IO should be done synchronously
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        ST_SYNCHRONOUS;
++        /// Allow mandatory locks on the filesystem
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        ST_MANDLOCK;
++        /// Write on file/directory/symlink
++        #[cfg(target_os = "linux")]
++        ST_WRITE;
++        /// Append-only file
++        #[cfg(target_os = "linux")]
++        ST_APPEND;
++        /// Immutable file
++        #[cfg(target_os = "linux")]
++        ST_IMMUTABLE;
++        /// Do not update access times on files
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        ST_NOATIME;
++        /// Do not update access times on files
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        ST_NODIRATIME;
++        /// Update access time relative to modify/change time
++        #[cfg(any(target_os = "android", all(target_os = "linux", not(target_env = "musl"))))]
++        ST_RELATIME;
++    }
++);
++
++/// Wrapper around the POSIX `statvfs` struct
++///
++/// For more information see the [`statvfs(3)` man pages](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_statvfs.h.html).
++// FIXME: Replace with repr(transparent)
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct Statvfs(libc::statvfs);
++
++impl Statvfs {
++    /// get the file system block size
++    pub fn block_size(&self) -> c_ulong {
++        self.0.f_bsize
++    }
++
++    /// Get the fundamental file system block size
++    pub fn fragment_size(&self) -> c_ulong {
++        self.0.f_frsize
++    }
++
++    /// Get the number of blocks.
++    ///
++    /// Units are in units of `fragment_size()`
++    pub fn blocks(&self) -> libc::fsblkcnt_t {
++        self.0.f_blocks
++    }
++
++    /// Get the number of free blocks in the file system
++    pub fn blocks_free(&self) -> libc::fsblkcnt_t {
++        self.0.f_bfree
++    }
++
++    /// Get the number of free blocks for unprivileged users
++    pub fn blocks_available(&self) -> libc::fsblkcnt_t {
++        self.0.f_bavail
++    }
++
++    /// Get the total number of file inodes
++    pub fn files(&self) -> libc::fsfilcnt_t {
++        self.0.f_files
++    }
++
++    /// Get the number of free file inodes
++    pub fn files_free(&self) -> libc::fsfilcnt_t {
++        self.0.f_ffree
++    }
++
++    /// Get the number of free file inodes for unprivileged users
++    pub fn files_available(&self) -> libc::fsfilcnt_t {
++        self.0.f_favail
++    }
++
++    /// Get the file system id
++    pub fn filesystem_id(&self) -> c_ulong {
++        self.0.f_fsid
++    }
++
++    /// Get the mount flags
++    pub fn flags(&self) -> FsFlags {
++        FsFlags::from_bits_truncate(self.0.f_flag)
++    }
++
++    /// Get the maximum filename length
++    pub fn name_max(&self) -> c_ulong {
++        self.0.f_namemax
++    }
++
++}
++
++/// Return a `Statvfs` object with information about the `path`
++pub fn statvfs<P: ?Sized + NixPath>(path: &P) -> Result<Statvfs> {
++    unsafe {
++        Errno::clear();
++        let mut stat: Statvfs = mem::uninitialized();
++        let res = path.with_nix_path(|path|
++            libc::statvfs(path.as_ptr(), &mut stat.0)
++        )?;
++
++        Errno::result(res).map(|_| stat)
++    }
++}
++
++/// Return a `Statvfs` object with information about `fd`
++pub fn fstatvfs<T: AsRawFd>(fd: &T) -> Result<Statvfs> {
++    unsafe {
++        Errno::clear();
++        let mut stat: Statvfs = mem::uninitialized();
++        Errno::result(libc::fstatvfs(fd.as_raw_fd(), &mut stat.0)).map(|_| stat)
++    }
++}
++
++#[cfg(test)]
++mod test {
++    use std::fs::File;
++    use sys::statvfs::*;
++
++    #[test]
++    fn statvfs_call() {
++        statvfs("/".as_bytes()).unwrap();
++    }
++
++    #[test]
++    fn fstatvfs_call() {
++        let root = File::open("/").unwrap();
++        fstatvfs(&root).unwrap();
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/sysinfo.rs b/third_party/rust/nix-0.15.0/src/sys/sysinfo.rs
+new file mode 100644
+index 0000000000000..4c8e38988886d
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/sysinfo.rs
+@@ -0,0 +1,72 @@
++use libc::{self, SI_LOAD_SHIFT};
++use std::{cmp, mem};
++use std::time::Duration;
++
++use Result;
++use errno::Errno;
++
++/// System info structure returned by `sysinfo`.
++#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
++pub struct SysInfo(libc::sysinfo);
++
++impl SysInfo {
++    /// Returns the load average tuple.
++    ///
++    /// The returned values represent the load average over time intervals of
++    /// 1, 5, and 15 minutes, respectively.
++    pub fn load_average(&self) -> (f64, f64, f64) {
++        (
++            self.0.loads[0] as f64 / (1 << SI_LOAD_SHIFT) as f64,
++            self.0.loads[1] as f64 / (1 << SI_LOAD_SHIFT) as f64,
++            self.0.loads[2] as f64 / (1 << SI_LOAD_SHIFT) as f64,
++        )
++    }
++
++    /// Returns the time since system boot.
++    pub fn uptime(&self) -> Duration {
++        // Truncate negative values to 0
++        Duration::from_secs(cmp::max(self.0.uptime, 0) as u64)
++    }
++
++    /// Current number of processes.
++    pub fn process_count(&self) -> u16 {
++        self.0.procs
++    }
++
++    /// Returns the amount of swap memory in Bytes.
++    pub fn swap_total(&self) -> u64 {
++        self.scale_mem(self.0.totalswap)
++    }
++
++    /// Returns the amount of unused swap memory in Bytes.
++    pub fn swap_free(&self) -> u64 {
++        self.scale_mem(self.0.freeswap)
++    }
++
++    /// Returns the total amount of installed RAM in Bytes.
++    pub fn ram_total(&self) -> u64 {
++        self.scale_mem(self.0.totalram)
++    }
++
++    /// Returns the amount of completely unused RAM in Bytes.
++    ///
++    /// "Unused" in this context means that the RAM in neither actively used by
++    /// programs, nor by the operating system as disk cache or buffer. It is
++    /// "wasted" RAM since it currently serves no purpose.
++    pub fn ram_unused(&self) -> u64 {
++        self.scale_mem(self.0.freeram)
++    }
++
++    fn scale_mem(&self, units: libc::c_ulong) -> u64 {
++        units as u64 * self.0.mem_unit as u64
++    }
++}
++
++/// Returns system information.
++///
++/// [See `sysinfo(2)`](http://man7.org/linux/man-pages/man2/sysinfo.2.html).
++pub fn sysinfo() -> Result<SysInfo> {
++    let mut info: libc::sysinfo = unsafe { mem::uninitialized() };
++    let res = unsafe { libc::sysinfo(&mut info) };
++    Errno::result(res).map(|_| SysInfo(info))
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/termios.rs b/third_party/rust/nix-0.15.0/src/sys/termios.rs
+new file mode 100644
+index 0000000000000..c7cdf10b461c1
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/termios.rs
+@@ -0,0 +1,1107 @@
++//! An interface for controlling asynchronous communication ports
++//!
++//! This interface provides a safe wrapper around the termios subsystem defined by POSIX. The
++//! underlying types are all implemented in libc for most platforms and either wrapped in safer
++//! types here or exported directly.
++//!
++//! If you are unfamiliar with the `termios` API, you should first read the
++//! [API documentation](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/termios.h.html) and
++//! then come back to understand how `nix` safely wraps it.
++//!
++//! It should be noted that this API incurs some runtime overhead above the base `libc` definitions.
++//! As this interface is not used with high-bandwidth information, this should be fine in most
++//! cases. The primary cost when using this API is that the `Termios` datatype here duplicates the
++//! standard fields of the underlying `termios` struct and uses safe type wrappers for those fields.
++//! This means that when crossing the FFI interface to the underlying C library, data is first
++//! copied into the underlying `termios` struct, then the operation is done, and the data is copied
++//! back (with additional sanity checking) into the safe wrapper types. The `termios` struct is
++//! relatively small across all platforms (on the order of 32-64 bytes).
++//!
++//! The following examples highlight some of the API use cases such that users coming from using C
++//! or reading the standard documentation will understand how to use the safe API exposed here.
++//!
++//! Example disabling processing of the end-of-file control character:
++//!
++//! ```
++//! # use self::nix::sys::termios::SpecialCharacterIndices::VEOF;
++//! # use self::nix::sys::termios::{_POSIX_VDISABLE, Termios};
++//! # let mut termios = unsafe { Termios::default_uninit() };
++//! termios.control_chars[VEOF as usize] = _POSIX_VDISABLE;
++//! ```
++//!
++//! The flags within `Termios` are defined as bitfields using the `bitflags` crate. This provides
++//! an interface for working with bitfields that is similar to working with the raw unsigned
++//! integer types but offers type safety because of the internal checking that values will always
++//! be a valid combination of the defined flags.
++//!
++//! An example showing some of the basic operations for interacting with the control flags:
++//!
++//! ```
++//! # use self::nix::sys::termios::{ControlFlags, Termios};
++//! # let mut termios = unsafe { Termios::default_uninit() };
++//! termios.control_flags & ControlFlags::CSIZE == ControlFlags::CS5;
++//! termios.control_flags |= ControlFlags::CS5;
++//! ```
++//!
++//! # Baud rates
++//!
++//! This API is not consistent across platforms when it comes to `BaudRate`: Android and Linux both
++//! only support the rates specified by the `BaudRate` enum through their termios API while the BSDs
++//! support arbitrary baud rates as the values of the `BaudRate` enum constants are the same integer
++//! value of the constant (`B9600` == `9600`). Therefore the `nix::termios` API uses the following
++//! conventions:
++//!
++//! * `cfgetispeed()` - Returns `u32` on BSDs, `BaudRate` on Android/Linux
++//! * `cfgetospeed()` - Returns `u32` on BSDs, `BaudRate` on Android/Linux
++//! * `cfsetispeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux
++//! * `cfsetospeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux
++//! * `cfsetspeed()` - Takes `u32` or `BaudRate` on BSDs, `BaudRate` on Android/Linux
++//!
++//! The most common use case of specifying a baud rate using the enum will work the same across
++//! platforms:
++//!
++//! ```rust
++//! # #[macro_use] extern crate nix;
++//! # use nix::sys::termios::{BaudRate, cfsetispeed, cfsetospeed, cfsetspeed, Termios};
++//! # fn main() {
++//! # let mut t = unsafe { Termios::default_uninit() };
++//! cfsetispeed(&mut t, BaudRate::B9600);
++//! cfsetospeed(&mut t, BaudRate::B9600);
++//! cfsetspeed(&mut t, BaudRate::B9600);
++//! # }
++//! ```
++//!
++//! Additionally round-tripping baud rates is consistent across platforms:
++//!
++//! ```rust
++//! # extern crate nix;
++//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetispeed, cfsetspeed, Termios};
++//! # fn main() {
++//! # let mut t = unsafe { Termios::default_uninit() };
++//! # cfsetspeed(&mut t, BaudRate::B9600);
++//! let speed = cfgetispeed(&t);
++//! assert!(speed == cfgetospeed(&t));
++//! cfsetispeed(&mut t, speed);
++//! # }
++//! ```
++//!
++//! On non-BSDs, `cfgetispeed()` and `cfgetospeed()` both return a `BaudRate`:
++//!
++// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version
++#![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
++                target_os = "macos", target_os = "netbsd", target_os = "openbsd"),
++            doc = " ```rust,ignore")]
++#![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
++                    target_os = "macos", target_os = "netbsd", target_os = "openbsd")),
++            doc = " ```rust")]
++//! # extern crate nix;
++//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios};
++//! # fn main() {
++//! # let mut t = unsafe { Termios::default_uninit() };
++//! # cfsetspeed(&mut t, BaudRate::B9600);
++//! assert!(cfgetispeed(&t) == BaudRate::B9600);
++//! assert!(cfgetospeed(&t) == BaudRate::B9600);
++//! # }
++//! ```
++//!
++//! But on the BSDs, `cfgetispeed()` and `cfgetospeed()` both return `u32`s:
++//!
++// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version
++#![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
++                target_os = "macos", target_os = "netbsd", target_os = "openbsd"),
++            doc = " ```rust")]
++#![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
++                    target_os = "macos", target_os = "netbsd", target_os = "openbsd")),
++            doc = " ```rust,ignore")]
++//! # extern crate nix;
++//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios};
++//! # fn main() {
++//! # let mut t = unsafe { Termios::default_uninit() };
++//! # cfsetspeed(&mut t, 9600u32);
++//! assert!(cfgetispeed(&t) == 9600u32);
++//! assert!(cfgetospeed(&t) == 9600u32);
++//! # }
++//! ```
++//!
++//! It's trivial to convert from a `BaudRate` to a `u32` on BSDs:
++//!
++// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version
++#![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
++                target_os = "macos", target_os = "netbsd", target_os = "openbsd"),
++            doc = " ```rust")]
++#![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
++                    target_os = "macos", target_os = "netbsd", target_os = "openbsd")),
++            doc = " ```rust,ignore")]
++//! # extern crate nix;
++//! # use nix::sys::termios::{BaudRate, cfgetispeed, cfsetspeed, Termios};
++//! # fn main() {
++//! # let mut t = unsafe { Termios::default_uninit() };
++//! # cfsetspeed(&mut t, 9600u32);
++//! assert!(cfgetispeed(&t) == BaudRate::B9600.into());
++//! assert!(u32::from(BaudRate::B9600) == 9600u32);
++//! # }
++//! ```
++//!
++//! And on BSDs you can specify arbitrary baud rates (**note** this depends on hardware support)
++//! by specifying baud rates directly using `u32`s:
++//!
++// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version
++#![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
++                target_os = "macos", target_os = "netbsd", target_os = "openbsd"),
++            doc = " ```rust")]
++#![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
++                    target_os = "macos", target_os = "netbsd", target_os = "openbsd")),
++            doc = " ```rust,ignore")]
++//! # extern crate nix;
++//! # use nix::sys::termios::{cfsetispeed, cfsetospeed, cfsetspeed, Termios};
++//! # fn main() {
++//! # let mut t = unsafe { Termios::default_uninit() };
++//! cfsetispeed(&mut t, 9600u32);
++//! cfsetospeed(&mut t, 9600u32);
++//! cfsetspeed(&mut t, 9600u32);
++//! # }
++//! ```
++use Result;
++use errno::Errno;
++use libc::{self, c_int, tcflag_t};
++use std::cell::{Ref, RefCell};
++use std::convert::From;
++use std::mem;
++use std::os::unix::io::RawFd;
++
++use ::unistd::Pid;
++
++/// Stores settings for the termios API
++///
++/// This is a wrapper around the `libc::termios` struct that provides a safe interface for the
++/// standard fields. The only safe way to obtain an instance of this struct is to extract it from
++/// an open port using `tcgetattr()`.
++#[derive(Clone, Debug, Eq, PartialEq)]
++pub struct Termios {
++    inner: RefCell<libc::termios>,
++    /// Input mode flags (see `termios.c_iflag` documentation)
++    pub input_flags: InputFlags,
++    /// Output mode flags (see `termios.c_oflag` documentation)
++    pub output_flags: OutputFlags,
++    /// Control mode flags (see `termios.c_cflag` documentation)
++    pub control_flags: ControlFlags,
++    /// Local mode flags (see `termios.c_lflag` documentation)
++    pub local_flags: LocalFlags,
++    /// Control characters (see `termios.c_cc` documentation)
++    pub control_chars: [libc::cc_t; NCCS],
++}
++
++impl Termios {
++    /// Exposes an immutable reference to the underlying `libc::termios` data structure.
++    ///
++    /// This can be used for interfacing with other FFI functions like:
++    ///
++    /// ```rust
++    /// # extern crate libc;
++    /// # extern crate nix;
++    /// # fn main() {
++    /// # use nix::sys::termios::Termios;
++    /// # let mut termios = unsafe { Termios::default_uninit() };
++    /// let inner_termios = termios.get_libc_termios();
++    /// unsafe { libc::cfgetispeed(&*inner_termios) };
++    /// # }
++    /// ```
++    ///
++    /// There is no public API exposed for functions that modify the underlying `libc::termios`
++    /// data because it requires additional work to maintain type safety.
++    // FIXME: Switch this over to use pub(crate)
++    #[doc(hidden)]
++    pub fn get_libc_termios(&self) -> Ref<libc::termios> {
++        {
++            let mut termios = self.inner.borrow_mut();
++            termios.c_iflag = self.input_flags.bits();
++            termios.c_oflag = self.output_flags.bits();
++            termios.c_cflag = self.control_flags.bits();
++            termios.c_lflag = self.local_flags.bits();
++            termios.c_cc = self.control_chars;
++        }
++        self.inner.borrow()
++    }
++
++    /// Exposes the inner `libc::termios` datastore within `Termios`.
++    ///
++    /// This is unsafe because if this is used to modify the inner libc::termios struct, it will not
++    /// automatically update the safe wrapper type around it. Therefore we disable docs to
++    /// effectively limit its use to nix internals. In this case it should also be paired with a
++    /// call to `update_wrapper()` so that the wrapper-type and internal representation stay
++    /// consistent.
++    unsafe fn get_libc_termios_mut(&mut self) -> *mut libc::termios {
++        {
++            let mut termios = self.inner.borrow_mut();
++            termios.c_iflag = self.input_flags.bits();
++            termios.c_oflag = self.output_flags.bits();
++            termios.c_cflag = self.control_flags.bits();
++            termios.c_lflag = self.local_flags.bits();
++            termios.c_cc = self.control_chars;
++        }
++        self.inner.as_ptr()
++    }
++
++    /// Allows for easily creating new `Termios` structs that will be overwritten with real data.
++    ///
++    /// This should only be used when the inner libc::termios struct will be overwritten before it's
++    /// read.
++    // FIXME: Switch this over to use pub(crate)
++    #[doc(hidden)]
++    pub unsafe fn default_uninit() -> Self {
++        Termios {
++            inner: RefCell::new(mem::uninitialized()),
++            input_flags: InputFlags::empty(),
++            output_flags: OutputFlags::empty(),
++            control_flags: ControlFlags::empty(),
++            local_flags: LocalFlags::empty(),
++            control_chars: [0 as libc::cc_t; NCCS],
++        }
++    }
++
++    /// Updates the wrapper values from the internal `libc::termios` data structure.
++    #[doc(hidden)]
++    pub fn update_wrapper(&mut self) {
++        let termios = *self.inner.borrow_mut();
++        self.input_flags = InputFlags::from_bits_truncate(termios.c_iflag);
++        self.output_flags = OutputFlags::from_bits_truncate(termios.c_oflag);
++        self.control_flags = ControlFlags::from_bits_truncate(termios.c_cflag);
++        self.local_flags = LocalFlags::from_bits_truncate(termios.c_lflag);
++        self.control_chars = termios.c_cc;
++    }
++}
++
++impl From<libc::termios> for Termios {
++    fn from(termios: libc::termios) -> Self {
++        Termios {
++            inner: RefCell::new(termios),
++            input_flags: InputFlags::from_bits_truncate(termios.c_iflag),
++            output_flags: OutputFlags::from_bits_truncate(termios.c_oflag),
++            control_flags: ControlFlags::from_bits_truncate(termios.c_cflag),
++            local_flags: LocalFlags::from_bits_truncate(termios.c_lflag),
++            control_chars: termios.c_cc,
++        }
++    }
++}
++
++impl From<Termios> for libc::termios {
++    fn from(termios: Termios) -> Self {
++        termios.inner.into_inner()
++    }
++}
++
++libc_enum!{
++    /// Baud rates supported by the system.
++    ///
++    /// For the BSDs, arbitrary baud rates can be specified by using `u32`s directly instead of this
++    /// enum.
++    ///
++    /// B0 is special and will disable the port.
++    #[cfg_attr(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64"), repr(u64))]
++    #[cfg_attr(not(all(any(target_os = "ios", target_os = "macos"), target_pointer_width = "64")), repr(u32))]
++    pub enum BaudRate {
++        B0,
++        B50,
++        B75,
++        B110,
++        B134,
++        B150,
++        B200,
++        B300,
++        B600,
++        B1200,
++        B1800,
++        B2400,
++        B4800,
++        #[cfg(any(target_os = "dragonfly",
++                target_os = "freebsd",
++                target_os = "macos",
++                target_os = "netbsd",
++                target_os = "openbsd"))]
++        B7200,
++        B9600,
++        #[cfg(any(target_os = "dragonfly",
++                target_os = "freebsd",
++                target_os = "macos",
++                target_os = "netbsd",
++                target_os = "openbsd"))]
++        B14400,
++        B19200,
++        #[cfg(any(target_os = "dragonfly",
++                target_os = "freebsd",
++                target_os = "macos",
++                target_os = "netbsd",
++                target_os = "openbsd"))]
++        B28800,
++        B38400,
++        B57600,
++        #[cfg(any(target_os = "dragonfly",
++                target_os = "freebsd",
++                target_os = "macos",
++                target_os = "netbsd",
++                target_os = "openbsd"))]
++        B76800,
++        B115200,
++        B230400,
++        #[cfg(any(target_os = "android",
++                  target_os = "freebsd",
++                  target_os = "linux",
++                  target_os = "netbsd"))]
++        B460800,
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        B500000,
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        B576000,
++        #[cfg(any(target_os = "android",
++                  target_os = "freebsd",
++                  target_os = "linux",
++                  target_os = "netbsd"))]
++        B921600,
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        B1000000,
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        B1152000,
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        B1500000,
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        B2000000,
++        #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
++        B2500000,
++        #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
++        B3000000,
++        #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
++        B3500000,
++        #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
++        B4000000,
++    }
++}
++
++impl From<libc::speed_t> for BaudRate {
++    fn from(s: libc::speed_t) -> BaudRate {
++
++        use libc::{B0, B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400, B4800,
++                   B9600, B19200, B38400, B57600, B115200, B230400};
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        use libc::{B500000, B576000, B1000000, B1152000, B1500000, B2000000};
++        #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
++        use libc::{B2500000, B3000000, B3500000, B4000000};
++        #[cfg(any(target_os = "dragonfly",
++                  target_os = "freebsd",
++                  target_os = "macos",
++                  target_os = "netbsd",
++                  target_os = "openbsd"))]
++        use libc::{B7200, B14400, B28800, B76800};
++        #[cfg(any(target_os = "android",
++                  target_os = "freebsd",
++                  target_os = "linux",
++                  target_os = "netbsd"))]
++        use libc::{B460800, B921600};
++
++        match s {
++            B0 => BaudRate::B0,
++            B50 => BaudRate::B50,
++            B75 => BaudRate::B75,
++            B110 => BaudRate::B110,
++            B134 => BaudRate::B134,
++            B150 => BaudRate::B150,
++            B200 => BaudRate::B200,
++            B300 => BaudRate::B300,
++            B600 => BaudRate::B600,
++            B1200 => BaudRate::B1200,
++            B1800 => BaudRate::B1800,
++            B2400 => BaudRate::B2400,
++            B4800 => BaudRate::B4800,
++            #[cfg(any(target_os = "dragonfly",
++                      target_os = "freebsd",
++                      target_os = "macos",
++                      target_os = "netbsd",
++                      target_os = "openbsd"))]
++            B7200 => BaudRate::B7200,
++            B9600 => BaudRate::B9600,
++            #[cfg(any(target_os = "dragonfly",
++                      target_os = "freebsd",
++                      target_os = "macos",
++                      target_os = "netbsd",
++                      target_os = "openbsd"))]
++            B14400 => BaudRate::B14400,
++            B19200 => BaudRate::B19200,
++            #[cfg(any(target_os = "dragonfly",
++                      target_os = "freebsd",
++                      target_os = "macos",
++                      target_os = "netbsd",
++                      target_os = "openbsd"))]
++            B28800 => BaudRate::B28800,
++            B38400 => BaudRate::B38400,
++            B57600 => BaudRate::B57600,
++            #[cfg(any(target_os = "dragonfly",
++                      target_os = "freebsd",
++                      target_os = "macos",
++                      target_os = "netbsd",
++                      target_os = "openbsd"))]
++            B76800 => BaudRate::B76800,
++            B115200 => BaudRate::B115200,
++            B230400 => BaudRate::B230400,
++            #[cfg(any(target_os = "android",
++                      target_os = "freebsd",
++                      target_os = "linux",
++                      target_os = "netbsd"))]
++            B460800 => BaudRate::B460800,
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            B500000 => BaudRate::B500000,
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            B576000 => BaudRate::B576000,
++            #[cfg(any(target_os = "android",
++                      target_os = "freebsd",
++                      target_os = "linux",
++                      target_os = "netbsd"))]
++            B921600 => BaudRate::B921600,
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            B1000000 => BaudRate::B1000000,
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            B1152000 => BaudRate::B1152000,
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            B1500000 => BaudRate::B1500000,
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            B2000000 => BaudRate::B2000000,
++            #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
++            B2500000 => BaudRate::B2500000,
++            #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
++            B3000000 => BaudRate::B3000000,
++            #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
++            B3500000 => BaudRate::B3500000,
++            #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
++            B4000000 => BaudRate::B4000000,
++            b => unreachable!("Invalid baud constant: {}", b),
++        }
++    }
++}
++
++// TODO: Include `TryFrom<u32> for BaudRate` once that API stabilizes
++#[cfg(any(target_os = "freebsd",
++          target_os = "dragonfly",
++          target_os = "ios",
++          target_os = "macos",
++          target_os = "netbsd",
++          target_os = "openbsd"))]
++impl From<BaudRate> for u32 {
++    fn from(b: BaudRate) -> u32 {
++        b as u32
++    }
++}
++
++// TODO: Add TCSASOFT, which will require treating this as a bitfield.
++libc_enum! {
++    /// Specify when a port configuration change should occur.
++    ///
++    /// Used as an argument to `tcsetattr()`
++    #[repr(i32)]
++    pub enum SetArg {
++        /// The change will occur immediately
++        TCSANOW,
++        /// The change occurs after all output has been written
++        TCSADRAIN,
++        /// Same as `TCSADRAIN`, but will also flush the input buffer
++        TCSAFLUSH,
++    }
++}
++
++libc_enum! {
++    /// Specify a combination of the input and output buffers to flush
++    ///
++    /// Used as an argument to `tcflush()`.
++    #[repr(i32)]
++    pub enum FlushArg {
++        /// Flush data that was received but not read
++        TCIFLUSH,
++        /// Flush data written but not transmitted
++        TCOFLUSH,
++        /// Flush both received data not read and written data not transmitted
++        TCIOFLUSH,
++    }
++}
++
++libc_enum! {
++    /// Specify how transmission flow should be altered
++    ///
++    /// Used as an argument to `tcflow()`.
++    #[repr(i32)]
++    pub enum FlowArg {
++        /// Suspend transmission
++        TCOOFF,
++        /// Resume transmission
++        TCOON,
++        /// Transmit a STOP character, which should disable a connected terminal device
++        TCIOFF,
++        /// Transmit a START character, which should re-enable a connected terminal device
++        TCION,
++    }
++}
++
++// TODO: Make this usable directly as a slice index.
++libc_enum! {
++    /// Indices into the `termios.c_cc` array for special characters.
++    #[repr(usize)]
++    pub enum SpecialCharacterIndices {
++        VDISCARD,
++        #[cfg(any(target_os = "dragonfly",
++                target_os = "freebsd",
++                target_os = "macos",
++                target_os = "netbsd",
++                target_os = "openbsd"))]
++        VDSUSP,
++        VEOF,
++        VEOL,
++        VEOL2,
++        VERASE,
++        #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++        VERASE2,
++        VINTR,
++        VKILL,
++        VLNEXT,
++        #[cfg(not(all(target_os = "linux", target_arch = "sparc64")))]
++        VMIN,
++        VQUIT,
++        VREPRINT,
++        VSTART,
++        #[cfg(any(target_os = "dragonfly",
++                target_os = "freebsd",
++                target_os = "macos",
++                target_os = "netbsd",
++                target_os = "openbsd"))]
++        VSTATUS,
++        VSTOP,
++        VSUSP,
++        #[cfg(target_os = "linux")]
++        VSWTC,
++        #[cfg(target_os = "haiku")]
++        VSWTCH,
++        #[cfg(not(all(target_os = "linux", target_arch = "sparc64")))]
++        VTIME,
++        VWERASE,
++        #[cfg(target_os = "dragonfly")]
++        VCHECKPT,
++    }
++}
++
++pub use libc::NCCS;
++#[cfg(any(target_os = "dragonfly",
++          target_os = "freebsd",
++          target_os = "linux",
++          target_os = "macos",
++          target_os = "netbsd",
++          target_os = "openbsd"))]
++pub use libc::_POSIX_VDISABLE;
++
++libc_bitflags! {
++    /// Flags for configuring the input mode of a terminal
++    pub struct InputFlags: tcflag_t {
++        IGNBRK;
++        BRKINT;
++        IGNPAR;
++        PARMRK;
++        INPCK;
++        ISTRIP;
++        INLCR;
++        IGNCR;
++        ICRNL;
++        IXON;
++        IXOFF;
++        IXANY;
++        IMAXBEL;
++        #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
++        IUTF8;
++    }
++}
++
++libc_bitflags! {
++    /// Flags for configuring the output mode of a terminal
++    pub struct OutputFlags: tcflag_t {
++        OPOST;
++        #[cfg(any(target_os = "android",
++                  target_os = "haiku",
++                  target_os = "linux",
++                  target_os = "openbsd"))]
++        OLCUC;
++        ONLCR;
++        OCRNL as tcflag_t;
++        ONOCR as tcflag_t;
++        ONLRET as tcflag_t;
++        #[cfg(any(target_os = "android",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        OFILL as tcflag_t;
++        #[cfg(any(target_os = "android",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        OFDEL as tcflag_t;
++        #[cfg(any(target_os = "android",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        NL0 as tcflag_t;
++        #[cfg(any(target_os = "android",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        NL1 as tcflag_t;
++        #[cfg(any(target_os = "android",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        CR0 as tcflag_t;
++        #[cfg(any(target_os = "android",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        CR1 as tcflag_t;
++        #[cfg(any(target_os = "android",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        CR2 as tcflag_t;
++        #[cfg(any(target_os = "android",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        CR3 as tcflag_t;
++        #[cfg(any(target_os = "android",
++                  target_os = "freebsd",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        TAB0 as tcflag_t;
++        #[cfg(any(target_os = "android",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        TAB1 as tcflag_t;
++        #[cfg(any(target_os = "android",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        TAB2 as tcflag_t;
++        #[cfg(any(target_os = "android",
++                  target_os = "freebsd",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        TAB3 as tcflag_t;
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        XTABS;
++        #[cfg(any(target_os = "android",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        BS0 as tcflag_t;
++        #[cfg(any(target_os = "android",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        BS1 as tcflag_t;
++        #[cfg(any(target_os = "android",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        VT0 as tcflag_t;
++        #[cfg(any(target_os = "android",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        VT1 as tcflag_t;
++        #[cfg(any(target_os = "android",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        FF0 as tcflag_t;
++        #[cfg(any(target_os = "android",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        FF1 as tcflag_t;
++        #[cfg(any(target_os = "freebsd",
++                  target_os = "dragonfly",
++                  target_os = "ios",
++                  target_os = "macos",
++                  target_os = "netbsd",
++                  target_os = "openbsd"))]
++        OXTABS;
++        #[cfg(any(target_os = "freebsd",
++                  target_os = "dragonfly",
++                  target_os = "macos",
++                  target_os = "netbsd",
++                  target_os = "openbsd"))]
++        ONOEOT as tcflag_t;
++
++        // Bitmasks for use with OutputFlags to select specific settings
++        // These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110
++        // is resolved.
++
++        #[cfg(any(target_os = "android",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        NLDLY as tcflag_t; // FIXME: Datatype needs to be corrected in libc for mac
++        #[cfg(any(target_os = "android",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        CRDLY as tcflag_t;
++        #[cfg(any(target_os = "android",
++                  target_os = "freebsd",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        TABDLY as tcflag_t;
++        #[cfg(any(target_os = "android",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        BSDLY as tcflag_t;
++        #[cfg(any(target_os = "android",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        VTDLY as tcflag_t;
++        #[cfg(any(target_os = "android",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos"))]
++        FFDLY as tcflag_t;
++    }
++}
++
++libc_bitflags! {
++    /// Flags for setting the control mode of a terminal
++    pub struct ControlFlags: tcflag_t {
++        #[cfg(any(target_os = "dragonfly",
++                  target_os = "freebsd",
++                  target_os = "ios",
++                  target_os = "macos",
++                  target_os = "netbsd",
++                  target_os = "openbsd"))]
++        CIGNORE;
++        CS5;
++        CS6;
++        CS7;
++        CS8;
++        CSTOPB;
++        CREAD;
++        PARENB;
++        PARODD;
++        HUPCL;
++        CLOCAL;
++        CRTSCTS;
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        CBAUD;
++        #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "mips"))))]
++        CMSPAR;
++        #[cfg(any(target_os = "android",
++                  all(target_os = "linux",
++                      not(any(target_arch = "powerpc", target_arch = "powerpc64")))))]
++        CIBAUD;
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        CBAUDEX;
++        #[cfg(any(target_os = "dragonfly",
++                  target_os = "freebsd",
++                  target_os = "macos",
++                  target_os = "netbsd",
++                  target_os = "openbsd"))]
++        MDMBUF;
++        #[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
++        CHWFLOW;
++        #[cfg(any(target_os = "dragonfly",
++                  target_os = "freebsd",
++                  target_os = "netbsd",
++                  target_os = "openbsd"))]
++        CCTS_OFLOW;
++        #[cfg(any(target_os = "dragonfly",
++                  target_os = "freebsd",
++                  target_os = "netbsd",
++                  target_os = "openbsd"))]
++        CRTS_IFLOW;
++        #[cfg(any(target_os = "dragonfly",
++                  target_os = "freebsd"))]
++        CDTR_IFLOW;
++        #[cfg(any(target_os = "dragonfly",
++                  target_os = "freebsd"))]
++        CDSR_OFLOW;
++        #[cfg(any(target_os = "dragonfly",
++                  target_os = "freebsd"))]
++        CCAR_OFLOW;
++
++        // Bitmasks for use with ControlFlags to select specific settings
++        // These should be moved to be a mask once https://github.com/rust-lang-nursery/bitflags/issues/110
++        // is resolved.
++
++        CSIZE;
++    }
++}
++
++libc_bitflags! {
++    /// Flags for setting any local modes
++    pub struct LocalFlags: tcflag_t {
++        ECHOKE;
++        ECHOE;
++        ECHOK;
++        ECHO;
++        ECHONL;
++        ECHOPRT;
++        ECHOCTL;
++        ISIG;
++        ICANON;
++        #[cfg(any(target_os = "freebsd",
++                  target_os = "dragonfly",
++                  target_os = "ios",
++                  target_os = "macos",
++                  target_os = "netbsd",
++                  target_os = "openbsd"))]
++        ALTWERASE;
++        IEXTEN;
++        EXTPROC;
++        TOSTOP;
++        FLUSHO;
++        #[cfg(any(target_os = "freebsd",
++                  target_os = "dragonfly",
++                  target_os = "ios",
++                  target_os = "macos",
++                  target_os = "netbsd",
++                  target_os = "openbsd"))]
++        NOKERNINFO;
++        PENDIN;
++        NOFLSH;
++    }
++}
++
++cfg_if!{
++    if #[cfg(any(target_os = "freebsd",
++                 target_os = "dragonfly",
++                 target_os = "ios",
++                 target_os = "macos",
++                 target_os = "netbsd",
++                 target_os = "openbsd"))] {
++        /// Get input baud rate (see
++        /// [cfgetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)).
++        ///
++        /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure.
++        pub fn cfgetispeed(termios: &Termios) -> u32 {
++            let inner_termios = termios.get_libc_termios();
++            unsafe { libc::cfgetispeed(&*inner_termios) as u32 }
++        }
++
++        /// Get output baud rate (see
++        /// [cfgetospeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)).
++        ///
++        /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure.
++        pub fn cfgetospeed(termios: &Termios) -> u32 {
++            let inner_termios = termios.get_libc_termios();
++            unsafe { libc::cfgetospeed(&*inner_termios) as u32 }
++        }
++
++        /// Set input baud rate (see
++        /// [cfsetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)).
++        ///
++        /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure.
++        pub fn cfsetispeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> {
++            let inner_termios = unsafe { termios.get_libc_termios_mut() };
++            let res = unsafe { libc::cfsetispeed(inner_termios, baud.into() as libc::speed_t) };
++            termios.update_wrapper();
++            Errno::result(res).map(drop)
++        }
++
++        /// Set output baud rate (see
++        /// [cfsetospeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)).
++        ///
++        /// `cfsetospeed()` sets the output baud rate in the given termios structure.
++        pub fn cfsetospeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> {
++            let inner_termios = unsafe { termios.get_libc_termios_mut() };
++            let res = unsafe { libc::cfsetospeed(inner_termios, baud.into() as libc::speed_t) };
++            termios.update_wrapper();
++            Errno::result(res).map(drop)
++        }
++
++        /// Set both the input and output baud rates (see
++        /// [termios(3)](https://www.freebsd.org/cgi/man.cgi?query=cfsetspeed)).
++        ///
++        /// `cfsetspeed()` sets the input and output baud rate in the given termios structure. Note that
++        /// this is part of the 4.4BSD standard and not part of POSIX.
++        pub fn cfsetspeed<T: Into<u32>>(termios: &mut Termios, baud: T) -> Result<()> {
++            let inner_termios = unsafe { termios.get_libc_termios_mut() };
++            let res = unsafe { libc::cfsetspeed(inner_termios, baud.into() as libc::speed_t) };
++            termios.update_wrapper();
++            Errno::result(res).map(drop)
++        }
++    } else {
++        /// Get input baud rate (see
++        /// [cfgetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)).
++        ///
++        /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure.
++        pub fn cfgetispeed(termios: &Termios) -> BaudRate {
++            let inner_termios = termios.get_libc_termios();
++            unsafe { libc::cfgetispeed(&*inner_termios) }.into()
++        }
++
++        /// Get output baud rate (see
++        /// [cfgetospeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)).
++        ///
++        /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure.
++        pub fn cfgetospeed(termios: &Termios) -> BaudRate {
++            let inner_termios = termios.get_libc_termios();
++            unsafe { libc::cfgetospeed(&*inner_termios) }.into()
++        }
++
++        /// Set input baud rate (see
++        /// [cfsetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetispeed.html)).
++        ///
++        /// `cfsetispeed()` sets the intput baud rate in the given `Termios` structure.
++        pub fn cfsetispeed(termios: &mut Termios, baud: BaudRate) -> Result<()> {
++            let inner_termios = unsafe { termios.get_libc_termios_mut() };
++            let res = unsafe { libc::cfsetispeed(inner_termios, baud as libc::speed_t) };
++            termios.update_wrapper();
++            Errno::result(res).map(drop)
++        }
++
++        /// Set output baud rate (see
++        /// [cfsetospeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfsetospeed.html)).
++        ///
++        /// `cfsetospeed()` sets the output baud rate in the given `Termios` structure.
++        pub fn cfsetospeed(termios: &mut Termios, baud: BaudRate) -> Result<()> {
++            let inner_termios = unsafe { termios.get_libc_termios_mut() };
++            let res = unsafe { libc::cfsetospeed(inner_termios, baud as libc::speed_t) };
++            termios.update_wrapper();
++            Errno::result(res).map(drop)
++        }
++
++        /// Set both the input and output baud rates (see
++        /// [termios(3)](https://www.freebsd.org/cgi/man.cgi?query=cfsetspeed)).
++        ///
++        /// `cfsetspeed()` sets the input and output baud rate in the given `Termios` structure. Note that
++        /// this is part of the 4.4BSD standard and not part of POSIX.
++        pub fn cfsetspeed(termios: &mut Termios, baud: BaudRate) -> Result<()> {
++            let inner_termios = unsafe { termios.get_libc_termios_mut() };
++            let res = unsafe { libc::cfsetspeed(inner_termios, baud as libc::speed_t) };
++            termios.update_wrapper();
++            Errno::result(res).map(drop)
++        }
++    }
++}
++
++/// Configures the port to something like the "raw" mode of the old Version 7 terminal driver (see
++/// [termios(3)](http://man7.org/linux/man-pages/man3/termios.3.html)).
++///
++/// `cfmakeraw()` configures the termios structure such that input is available character-by-
++/// character, echoing is disabled, and all special input and output processing is disabled. Note
++/// that this is a non-standard function, but is available on Linux and BSDs.
++pub fn cfmakeraw(termios: &mut Termios) {
++    let inner_termios = unsafe { termios.get_libc_termios_mut() };
++    unsafe {
++        libc::cfmakeraw(inner_termios);
++    }
++    termios.update_wrapper();
++}
++
++/// Configures the port to "sane" mode (like the configuration of a newly created terminal) (see
++/// [tcsetattr(3)](https://www.freebsd.org/cgi/man.cgi?query=tcsetattr)).
++///
++/// Note that this is a non-standard function, available on FreeBSD.
++#[cfg(target_os = "freebsd")]
++pub fn cfmakesane(termios: &mut Termios) {
++    let inner_termios = unsafe { termios.get_libc_termios_mut() };
++    unsafe {
++        libc::cfmakesane(inner_termios);
++    }
++    termios.update_wrapper();
++}
++
++/// Return the configuration of a port
++/// [tcgetattr(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetattr.html)).
++///
++/// `tcgetattr()` returns a `Termios` structure with the current configuration for a port. Modifying
++/// this structure *will not* reconfigure the port, instead the modifications should be done to
++/// the `Termios` structure and then the port should be reconfigured using `tcsetattr()`.
++pub fn tcgetattr(fd: RawFd) -> Result<Termios> {
++    let mut termios: libc::termios = unsafe { mem::uninitialized() };
++
++    let res = unsafe { libc::tcgetattr(fd, &mut termios) };
++
++    Errno::result(res)?;
++
++    Ok(termios.into())
++}
++
++/// Set the configuration for a terminal (see
++/// [tcsetattr(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetattr.html)).
++///
++/// `tcsetattr()` reconfigures the given port based on a given `Termios` structure. This change
++/// takes affect at a time specified by `actions`. Note that this function may return success if
++/// *any* of the parameters were successfully set, not only if all were set successfully.
++pub fn tcsetattr(fd: RawFd, actions: SetArg, termios: &Termios) -> Result<()> {
++    let inner_termios = termios.get_libc_termios();
++    Errno::result(unsafe { libc::tcsetattr(fd, actions as c_int, &*inner_termios) }).map(drop)
++}
++
++/// Block until all output data is written (see
++/// [tcdrain(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcdrain.html)).
++pub fn tcdrain(fd: RawFd) -> Result<()> {
++    Errno::result(unsafe { libc::tcdrain(fd) }).map(drop)
++}
++
++/// Suspend or resume the transmission or reception of data (see
++/// [tcflow(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflow.html)).
++///
++/// `tcflow()` suspends of resumes the transmission or reception of data for the given port
++/// depending on the value of `action`.
++pub fn tcflow(fd: RawFd, action: FlowArg) -> Result<()> {
++    Errno::result(unsafe { libc::tcflow(fd, action as c_int) }).map(drop)
++}
++
++/// Discard data in the output or input queue (see
++/// [tcflush(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcflush.html)).
++///
++/// `tcflush()` will discard data for a terminal port in the input queue, output queue, or both
++/// depending on the value of `action`.
++pub fn tcflush(fd: RawFd, action: FlushArg) -> Result<()> {
++    Errno::result(unsafe { libc::tcflush(fd, action as c_int) }).map(drop)
++}
++
++/// Send a break for a specific duration (see
++/// [tcsendbreak(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsendbreak.html)).
++///
++/// When using asynchronous data transmission `tcsendbreak()` will transmit a continuous stream
++/// of zero-valued bits for an implementation-defined duration.
++pub fn tcsendbreak(fd: RawFd, duration: c_int) -> Result<()> {
++    Errno::result(unsafe { libc::tcsendbreak(fd, duration) }).map(drop)
++}
++
++/// Get the session controlled by the given terminal (see
++/// [tcgetsid(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetsid.html)).
++pub fn tcgetsid(fd: RawFd) -> Result<Pid> {
++    let res = unsafe { libc::tcgetsid(fd) };
++
++    Errno::result(res).map(Pid::from_raw)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/time.rs b/third_party/rust/nix-0.15.0/src/sys/time.rs
+new file mode 100644
+index 0000000000000..3ad57543b18a7
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/time.rs
+@@ -0,0 +1,542 @@
++use std::{cmp, fmt, ops};
++use std::convert::From;
++use libc::{c_long, timespec, timeval};
++pub use libc::{time_t, suseconds_t};
++
++pub trait TimeValLike: Sized {
++    #[inline]
++    fn zero() -> Self {
++        Self::seconds(0)
++    }
++
++    #[inline]
++    fn hours(hours: i64) -> Self {
++        let secs = hours.checked_mul(SECS_PER_HOUR)
++            .expect("TimeValLike::hours ouf of bounds");
++        Self::seconds(secs)
++    }
++
++    #[inline]
++    fn minutes(minutes: i64) -> Self {
++        let secs = minutes.checked_mul(SECS_PER_MINUTE)
++            .expect("TimeValLike::minutes out of bounds");
++        Self::seconds(secs)
++    }
++
++    fn seconds(seconds: i64) -> Self;
++    fn milliseconds(milliseconds: i64) -> Self;
++    fn microseconds(microseconds: i64) -> Self;
++    fn nanoseconds(nanoseconds: i64) -> Self;
++
++    #[inline]
++    fn num_hours(&self) -> i64 {
++        self.num_seconds() / 3600
++    }
++
++    #[inline]
++    fn num_minutes(&self) -> i64 {
++        self.num_seconds() / 60
++    }
++
++    fn num_seconds(&self) -> i64;
++    fn num_milliseconds(&self) -> i64;
++    fn num_microseconds(&self) -> i64;
++    fn num_nanoseconds(&self) -> i64;
++}
++
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct TimeSpec(timespec);
++
++const NANOS_PER_SEC: i64 = 1_000_000_000;
++const SECS_PER_MINUTE: i64 = 60;
++const SECS_PER_HOUR: i64 = 3600;
++
++#[cfg(target_pointer_width = "64")]
++const TS_MAX_SECONDS: i64 = (::std::i64::MAX / NANOS_PER_SEC) - 1;
++
++#[cfg(target_pointer_width = "32")]
++const TS_MAX_SECONDS: i64 = ::std::isize::MAX as i64;
++
++const TS_MIN_SECONDS: i64 = -TS_MAX_SECONDS;
++
++
++impl AsRef<timespec> for TimeSpec {
++    fn as_ref(&self) -> &timespec {
++        &self.0
++    }
++}
++
++impl Ord for TimeSpec {
++    // The implementation of cmp is simplified by assuming that the struct is
++    // normalized.  That is, tv_nsec must always be within [0, 1_000_000_000)
++    fn cmp(&self, other: &TimeSpec) -> cmp::Ordering {
++        if self.tv_sec() == other.tv_sec() {
++            self.tv_nsec().cmp(&other.tv_nsec())
++        } else {
++            self.tv_sec().cmp(&other.tv_sec())
++        }
++    }
++}
++
++impl PartialOrd for TimeSpec {
++    fn partial_cmp(&self, other: &TimeSpec) -> Option<cmp::Ordering> {
++        Some(self.cmp(other))
++    }
++}
++
++impl TimeValLike for TimeSpec {
++    #[inline]
++    fn seconds(seconds: i64) -> TimeSpec {
++        assert!(seconds >= TS_MIN_SECONDS && seconds <= TS_MAX_SECONDS,
++                "TimeSpec out of bounds; seconds={}", seconds);
++        TimeSpec(timespec {tv_sec: seconds as time_t, tv_nsec: 0 })
++    }
++
++    #[inline]
++    fn milliseconds(milliseconds: i64) -> TimeSpec {
++        let nanoseconds = milliseconds.checked_mul(1_000_000)
++            .expect("TimeSpec::milliseconds out of bounds");
++
++        TimeSpec::nanoseconds(nanoseconds)
++    }
++
++    /// Makes a new `TimeSpec` with given number of microseconds.
++    #[inline]
++    fn microseconds(microseconds: i64) -> TimeSpec {
++        let nanoseconds = microseconds.checked_mul(1_000)
++            .expect("TimeSpec::milliseconds out of bounds");
++
++        TimeSpec::nanoseconds(nanoseconds)
++    }
++
++    /// Makes a new `TimeSpec` with given number of nanoseconds.
++    #[inline]
++    fn nanoseconds(nanoseconds: i64) -> TimeSpec {
++        let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC);
++        assert!(secs >= TS_MIN_SECONDS && secs <= TS_MAX_SECONDS,
++                "TimeSpec out of bounds");
++        TimeSpec(timespec {tv_sec: secs as time_t,
++                           tv_nsec: nanos as c_long })
++    }
++
++    fn num_seconds(&self) -> i64 {
++        if self.tv_sec() < 0 && self.tv_nsec() > 0 {
++            (self.tv_sec() + 1) as i64
++        } else {
++            self.tv_sec() as i64
++        }
++    }
++
++    fn num_milliseconds(&self) -> i64 {
++        self.num_nanoseconds() / 1_000_000
++    }
++
++    fn num_microseconds(&self) -> i64 {
++        self.num_nanoseconds() / 1_000_000_000
++    }
++
++    fn num_nanoseconds(&self) -> i64 {
++        let secs = self.num_seconds() * 1_000_000_000;
++        let nsec = self.nanos_mod_sec();
++        secs + nsec as i64
++    }
++}
++
++impl TimeSpec {
++    fn nanos_mod_sec(&self) -> c_long {
++        if self.tv_sec() < 0 && self.tv_nsec() > 0 {
++            self.tv_nsec() - NANOS_PER_SEC as c_long
++        } else {
++            self.tv_nsec()
++        }
++    }
++
++    pub fn tv_sec(&self) -> time_t {
++        self.0.tv_sec
++    }
++
++    pub fn tv_nsec(&self) -> c_long {
++        self.0.tv_nsec
++    }
++}
++
++impl ops::Neg for TimeSpec {
++    type Output = TimeSpec;
++
++    fn neg(self) -> TimeSpec {
++        TimeSpec::nanoseconds(-self.num_nanoseconds())
++    }
++}
++
++impl ops::Add for TimeSpec {
++    type Output = TimeSpec;
++
++    fn add(self, rhs: TimeSpec) -> TimeSpec {
++        TimeSpec::nanoseconds(
++            self.num_nanoseconds() + rhs.num_nanoseconds())
++    }
++}
++
++impl ops::Sub for TimeSpec {
++    type Output = TimeSpec;
++
++    fn sub(self, rhs: TimeSpec) -> TimeSpec {
++        TimeSpec::nanoseconds(
++            self.num_nanoseconds() - rhs.num_nanoseconds())
++    }
++}
++
++impl ops::Mul<i32> for TimeSpec {
++    type Output = TimeSpec;
++
++    fn mul(self, rhs: i32) -> TimeSpec {
++        let usec = self.num_nanoseconds().checked_mul(rhs as i64)
++            .expect("TimeSpec multiply out of bounds");
++
++        TimeSpec::nanoseconds(usec)
++    }
++}
++
++impl ops::Div<i32> for TimeSpec {
++    type Output = TimeSpec;
++
++    fn div(self, rhs: i32) -> TimeSpec {
++        let usec = self.num_nanoseconds() / rhs as i64;
++        TimeSpec::nanoseconds(usec)
++    }
++}
++
++impl fmt::Display for TimeSpec {
++    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++        let (abs, sign) = if self.tv_sec() < 0 {
++            (-*self, "-")
++        } else {
++            (*self, "")
++        };
++
++        let sec = abs.tv_sec();
++
++        write!(f, "{}", sign)?;
++
++        if abs.tv_nsec() == 0 {
++            if abs.tv_sec() == 1 {
++                write!(f, "{} second", sec)?;
++            } else {
++                write!(f, "{} seconds", sec)?;
++            }
++        } else if abs.tv_nsec() % 1_000_000 == 0 {
++            write!(f, "{}.{:03} seconds", sec, abs.tv_nsec() / 1_000_000)?;
++        } else if abs.tv_nsec() % 1_000 == 0 {
++            write!(f, "{}.{:06} seconds", sec, abs.tv_nsec() / 1_000)?;
++        } else {
++            write!(f, "{}.{:09} seconds", sec, abs.tv_nsec())?;
++        }
++
++        Ok(())
++    }
++}
++
++
++
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct TimeVal(timeval);
++
++const MICROS_PER_SEC: i64 = 1_000_000;
++
++#[cfg(target_pointer_width = "64")]
++const TV_MAX_SECONDS: i64 = (::std::i64::MAX / MICROS_PER_SEC) - 1;
++
++#[cfg(target_pointer_width = "32")]
++const TV_MAX_SECONDS: i64 = ::std::isize::MAX as i64;
++
++const TV_MIN_SECONDS: i64 = -TV_MAX_SECONDS;
++
++impl AsRef<timeval> for TimeVal {
++    fn as_ref(&self) -> &timeval {
++        &self.0
++    }
++}
++
++impl Ord for TimeVal {
++    // The implementation of cmp is simplified by assuming that the struct is
++    // normalized.  That is, tv_usec must always be within [0, 1_000_000)
++    fn cmp(&self, other: &TimeVal) -> cmp::Ordering {
++        if self.tv_sec() == other.tv_sec() {
++            self.tv_usec().cmp(&other.tv_usec())
++        } else {
++            self.tv_sec().cmp(&other.tv_sec())
++        }
++    }
++}
++
++impl PartialOrd for TimeVal {
++    fn partial_cmp(&self, other: &TimeVal) -> Option<cmp::Ordering> {
++        Some(self.cmp(other))
++    }
++}
++
++impl TimeValLike for TimeVal {
++    #[inline]
++    fn seconds(seconds: i64) -> TimeVal {
++        assert!(seconds >= TV_MIN_SECONDS && seconds <= TV_MAX_SECONDS,
++                "TimeVal out of bounds; seconds={}", seconds);
++        TimeVal(timeval {tv_sec: seconds as time_t, tv_usec: 0 })
++    }
++
++    #[inline]
++    fn milliseconds(milliseconds: i64) -> TimeVal {
++        let microseconds = milliseconds.checked_mul(1_000)
++            .expect("TimeVal::milliseconds out of bounds");
++
++        TimeVal::microseconds(microseconds)
++    }
++
++    /// Makes a new `TimeVal` with given number of microseconds.
++    #[inline]
++    fn microseconds(microseconds: i64) -> TimeVal {
++        let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
++        assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS,
++                "TimeVal out of bounds");
++        TimeVal(timeval {tv_sec: secs as time_t,
++                           tv_usec: micros as suseconds_t })
++    }
++
++    /// Makes a new `TimeVal` with given number of nanoseconds.  Some precision
++    /// will be lost
++    #[inline]
++    fn nanoseconds(nanoseconds: i64) -> TimeVal {
++        let microseconds = nanoseconds / 1000;
++        let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
++        assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS,
++                "TimeVal out of bounds");
++        TimeVal(timeval {tv_sec: secs as time_t,
++                           tv_usec: micros as suseconds_t })
++    }
++
++    fn num_seconds(&self) -> i64 {
++        if self.tv_sec() < 0 && self.tv_usec() > 0 {
++            (self.tv_sec() + 1) as i64
++        } else {
++            self.tv_sec() as i64
++        }
++    }
++
++    fn num_milliseconds(&self) -> i64 {
++        self.num_microseconds() / 1_000
++    }
++
++    fn num_microseconds(&self) -> i64 {
++        let secs = self.num_seconds() * 1_000_000;
++        let usec = self.micros_mod_sec();
++        secs + usec as i64
++    }
++
++    fn num_nanoseconds(&self) -> i64 {
++        self.num_microseconds() * 1_000
++    }
++}
++
++impl TimeVal {
++    fn micros_mod_sec(&self) -> suseconds_t {
++        if self.tv_sec() < 0 && self.tv_usec() > 0 {
++            self.tv_usec() - MICROS_PER_SEC as suseconds_t
++        } else {
++            self.tv_usec()
++        }
++    }
++
++    pub fn tv_sec(&self) -> time_t {
++        self.0.tv_sec
++    }
++
++    pub fn tv_usec(&self) -> suseconds_t {
++        self.0.tv_usec
++    }
++}
++
++impl ops::Neg for TimeVal {
++    type Output = TimeVal;
++
++    fn neg(self) -> TimeVal {
++        TimeVal::microseconds(-self.num_microseconds())
++    }
++}
++
++impl ops::Add for TimeVal {
++    type Output = TimeVal;
++
++    fn add(self, rhs: TimeVal) -> TimeVal {
++        TimeVal::microseconds(
++            self.num_microseconds() + rhs.num_microseconds())
++    }
++}
++
++impl ops::Sub for TimeVal {
++    type Output = TimeVal;
++
++    fn sub(self, rhs: TimeVal) -> TimeVal {
++        TimeVal::microseconds(
++            self.num_microseconds() - rhs.num_microseconds())
++    }
++}
++
++impl ops::Mul<i32> for TimeVal {
++    type Output = TimeVal;
++
++    fn mul(self, rhs: i32) -> TimeVal {
++        let usec = self.num_microseconds().checked_mul(rhs as i64)
++            .expect("TimeVal multiply out of bounds");
++
++        TimeVal::microseconds(usec)
++    }
++}
++
++impl ops::Div<i32> for TimeVal {
++    type Output = TimeVal;
++
++    fn div(self, rhs: i32) -> TimeVal {
++        let usec = self.num_microseconds() / rhs as i64;
++        TimeVal::microseconds(usec)
++    }
++}
++
++impl fmt::Display for TimeVal {
++    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++        let (abs, sign) = if self.tv_sec() < 0 {
++            (-*self, "-")
++        } else {
++            (*self, "")
++        };
++
++        let sec = abs.tv_sec();
++
++        write!(f, "{}", sign)?;
++
++        if abs.tv_usec() == 0 {
++            if abs.tv_sec() == 1 {
++                write!(f, "{} second", sec)?;
++            } else {
++                write!(f, "{} seconds", sec)?;
++            }
++        } else if abs.tv_usec() % 1000 == 0 {
++            write!(f, "{}.{:03} seconds", sec, abs.tv_usec() / 1000)?;
++        } else {
++            write!(f, "{}.{:06} seconds", sec, abs.tv_usec())?;
++        }
++
++        Ok(())
++    }
++}
++
++impl From<timeval> for TimeVal {
++    fn from(tv: timeval) -> Self {
++        TimeVal(tv)
++    }
++}
++
++#[inline]
++fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
++    (div_floor_64(this, other), mod_floor_64(this, other))
++}
++
++#[inline]
++fn div_floor_64(this: i64, other: i64) -> i64 {
++    match div_rem_64(this, other) {
++        (d, r) if (r > 0 && other < 0)
++               || (r < 0 && other > 0) => d - 1,
++        (d, _)                         => d,
++    }
++}
++
++#[inline]
++fn mod_floor_64(this: i64, other: i64) -> i64 {
++    match this % other {
++        r if (r > 0 && other < 0)
++          || (r < 0 && other > 0) => r + other,
++        r                         => r,
++    }
++}
++
++#[inline]
++fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
++    (this / other, this % other)
++}
++
++#[cfg(test)]
++mod test {
++    use super::{TimeSpec, TimeVal, TimeValLike};
++
++    #[test]
++    pub fn test_timespec() {
++        assert!(TimeSpec::seconds(1) != TimeSpec::zero());
++        assert_eq!(TimeSpec::seconds(1) + TimeSpec::seconds(2),
++                   TimeSpec::seconds(3));
++        assert_eq!(TimeSpec::minutes(3) + TimeSpec::seconds(2),
++                   TimeSpec::seconds(182));
++    }
++
++    #[test]
++    pub fn test_timespec_neg() {
++        let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123);
++        let b = TimeSpec::seconds(-1) + TimeSpec::nanoseconds(-123);
++
++        assert_eq!(a, -b);
++    }
++
++    #[test]
++    pub fn test_timespec_ord() {
++        assert!(TimeSpec::seconds(1) == TimeSpec::nanoseconds(1_000_000_000));
++        assert!(TimeSpec::seconds(1) < TimeSpec::nanoseconds(1_000_000_001));
++        assert!(TimeSpec::seconds(1) > TimeSpec::nanoseconds(999_999_999));
++        assert!(TimeSpec::seconds(-1) < TimeSpec::nanoseconds(-999_999_999));
++        assert!(TimeSpec::seconds(-1) > TimeSpec::nanoseconds(-1_000_000_001));
++    }
++
++    #[test]
++    pub fn test_timespec_fmt() {
++        assert_eq!(TimeSpec::zero().to_string(), "0 seconds");
++        assert_eq!(TimeSpec::seconds(42).to_string(), "42 seconds");
++        assert_eq!(TimeSpec::milliseconds(42).to_string(), "0.042 seconds");
++        assert_eq!(TimeSpec::microseconds(42).to_string(), "0.000042 seconds");
++        assert_eq!(TimeSpec::nanoseconds(42).to_string(), "0.000000042 seconds");
++        assert_eq!(TimeSpec::seconds(-86401).to_string(), "-86401 seconds");
++    }
++
++    #[test]
++    pub fn test_timeval() {
++        assert!(TimeVal::seconds(1) != TimeVal::zero());
++        assert_eq!(TimeVal::seconds(1) + TimeVal::seconds(2),
++                   TimeVal::seconds(3));
++        assert_eq!(TimeVal::minutes(3) + TimeVal::seconds(2),
++                   TimeVal::seconds(182));
++    }
++
++    #[test]
++    pub fn test_timeval_ord() {
++        assert!(TimeVal::seconds(1) == TimeVal::microseconds(1_000_000));
++        assert!(TimeVal::seconds(1) < TimeVal::microseconds(1_000_001));
++        assert!(TimeVal::seconds(1) > TimeVal::microseconds(999_999));
++        assert!(TimeVal::seconds(-1) < TimeVal::microseconds(-999_999));
++        assert!(TimeVal::seconds(-1) > TimeVal::microseconds(-1_000_001));
++    }
++
++    #[test]
++    pub fn test_timeval_neg() {
++        let a = TimeVal::seconds(1) + TimeVal::microseconds(123);
++        let b = TimeVal::seconds(-1) + TimeVal::microseconds(-123);
++
++        assert_eq!(a, -b);
++    }
++
++    #[test]
++    pub fn test_timeval_fmt() {
++        assert_eq!(TimeVal::zero().to_string(), "0 seconds");
++        assert_eq!(TimeVal::seconds(42).to_string(), "42 seconds");
++        assert_eq!(TimeVal::milliseconds(42).to_string(), "0.042 seconds");
++        assert_eq!(TimeVal::microseconds(42).to_string(), "0.000042 seconds");
++        assert_eq!(TimeVal::nanoseconds(1402).to_string(), "0.000001 seconds");
++        assert_eq!(TimeVal::seconds(-86401).to_string(), "-86401 seconds");
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/uio.rs b/third_party/rust/nix-0.15.0/src/sys/uio.rs
+new file mode 100644
+index 0000000000000..d089084eed711
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/uio.rs
+@@ -0,0 +1,194 @@
++// Silence invalid warnings due to rust-lang/rust#16719
++#![allow(improper_ctypes)]
++
++use Result;
++use errno::Errno;
++use libc::{self, c_int, c_void, size_t, off_t};
++use std::marker::PhantomData;
++use std::os::unix::io::RawFd;
++
++pub fn writev(fd: RawFd, iov: &[IoVec<&[u8]>]) -> Result<usize> {
++    let res = unsafe { libc::writev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) };
++
++    Errno::result(res).map(|r| r as usize)
++}
++
++pub fn readv(fd: RawFd, iov: &mut [IoVec<&mut [u8]>]) -> Result<usize> {
++    let res = unsafe { libc::readv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) };
++
++    Errno::result(res).map(|r| r as usize)
++}
++
++/// Write to `fd` at `offset` from buffers in `iov`.
++///
++/// Buffers in `iov` will be written in order until all buffers have been written
++/// or an error occurs. The file offset is not changed.
++///
++/// See also: [`writev`](fn.writev.html) and [`pwrite`](fn.pwrite.html)
++#[cfg(any(target_os = "dragonfly",
++          target_os = "freebsd",
++          target_os = "linux",
++          target_os = "netbsd",
++          target_os = "openbsd"))]
++pub fn pwritev(fd: RawFd, iov: &[IoVec<&[u8]>],
++               offset: off_t) -> Result<usize> {
++    let res = unsafe {
++        libc::pwritev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset)
++    };
++
++    Errno::result(res).map(|r| r as usize)
++}
++
++/// Read from `fd` at `offset` filling buffers in `iov`.
++///
++/// Buffers in `iov` will be filled in order until all buffers have been filled,
++/// no more bytes are available, or an error occurs. The file offset is not
++/// changed.
++///
++/// See also: [`readv`](fn.readv.html) and [`pread`](fn.pread.html)
++#[cfg(any(target_os = "dragonfly",
++          target_os = "freebsd",
++          target_os = "linux",
++          target_os = "netbsd",
++          target_os = "openbsd"))]
++pub fn preadv(fd: RawFd, iov: &[IoVec<&mut [u8]>],
++              offset: off_t) -> Result<usize> {
++    let res = unsafe {
++        libc::preadv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int, offset)
++    };
++
++    Errno::result(res).map(|r| r as usize)
++}
++
++pub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result<usize> {
++    let res = unsafe {
++        libc::pwrite(fd, buf.as_ptr() as *const c_void, buf.len() as size_t,
++                    offset)
++    };
++
++    Errno::result(res).map(|r| r as usize)
++}
++
++pub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result<usize>{
++    let res = unsafe {
++        libc::pread(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t,
++                   offset)
++    };
++
++    Errno::result(res).map(|r| r as usize)
++}
++
++/// A slice of memory in a remote process, starting at address `base`
++/// and consisting of `len` bytes.
++///
++/// This is the same underlying C structure as [`IoVec`](struct.IoVec.html),
++/// except that it refers to memory in some other process, and is
++/// therefore not represented in Rust by an actual slice as `IoVec` is. It
++/// is used with [`process_vm_readv`](fn.process_vm_readv.html)
++/// and [`process_vm_writev`](fn.process_vm_writev.html).
++#[cfg(target_os = "linux")]
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct RemoteIoVec {
++    /// The starting address of this slice (`iov_base`).
++    pub base: usize,
++    /// The number of bytes in this slice (`iov_len`).
++    pub len: usize,
++}
++
++/// Write data directly to another process's virtual memory
++/// (see [`process_vm_writev`(2)]).
++///
++/// `local_iov` is a list of [`IoVec`]s containing the data to be written,
++/// and `remote_iov` is a list of [`RemoteIoVec`]s identifying where the
++/// data should be written in the target process. On success, returns the
++/// number of bytes written, which will always be a whole
++/// number of `remote_iov` chunks.
++///
++/// This requires the same permissions as debugging the process using
++/// [ptrace]: you must either be a privileged process (with
++/// `CAP_SYS_PTRACE`), or you must be running as the same user as the
++/// target process and the OS must have unprivileged debugging enabled.
++///
++/// This function is only available on Linux.
++///
++/// [`process_vm_writev`(2)]: http://man7.org/linux/man-pages/man2/process_vm_writev.2.html
++/// [ptrace]: ../ptrace/index.html
++/// [`IoVec`]: struct.IoVec.html
++/// [`RemoteIoVec`]: struct.RemoteIoVec.html
++#[cfg(target_os = "linux")]
++pub fn process_vm_writev(pid: ::unistd::Pid, local_iov: &[IoVec<&[u8]>], remote_iov: &[RemoteIoVec]) -> Result<usize> {
++    let res = unsafe {
++        libc::process_vm_writev(pid.into(),
++                                local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong,
++                                remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0)
++    };
++
++    Errno::result(res).map(|r| r as usize)
++}
++
++/// Read data directly from another process's virtual memory
++/// (see [`process_vm_readv`(2)]).
++///
++/// `local_iov` is a list of [`IoVec`]s containing the buffer to copy
++/// data into, and `remote_iov` is a list of [`RemoteIoVec`]s identifying
++/// where the source data is in the target process. On success,
++/// returns the number of bytes written, which will always be a whole
++/// number of `remote_iov` chunks.
++///
++/// This requires the same permissions as debugging the process using
++/// [`ptrace`]: you must either be a privileged process (with
++/// `CAP_SYS_PTRACE`), or you must be running as the same user as the
++/// target process and the OS must have unprivileged debugging enabled.
++///
++/// This function is only available on Linux.
++///
++/// [`process_vm_readv`(2)]: http://man7.org/linux/man-pages/man2/process_vm_readv.2.html
++/// [`ptrace`]: ../ptrace/index.html
++/// [`IoVec`]: struct.IoVec.html
++/// [`RemoteIoVec`]: struct.RemoteIoVec.html
++#[cfg(any(target_os = "linux"))]
++pub fn process_vm_readv(pid: ::unistd::Pid, local_iov: &[IoVec<&mut [u8]>], remote_iov: &[RemoteIoVec]) -> Result<usize> {
++    let res = unsafe {
++        libc::process_vm_readv(pid.into(),
++                               local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong,
++                               remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0)
++    };
++
++    Errno::result(res).map(|r| r as usize)
++}
++
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct IoVec<T>(libc::iovec, PhantomData<T>);
++
++impl<T> IoVec<T> {
++    #[inline]
++    pub fn as_slice(&self) -> &[u8] {
++        use std::slice;
++
++        unsafe {
++            slice::from_raw_parts(
++                self.0.iov_base as *const u8,
++                self.0.iov_len as usize)
++        }
++    }
++}
++
++impl<'a> IoVec<&'a [u8]> {
++    pub fn from_slice(buf: &'a [u8]) -> IoVec<&'a [u8]> {
++        IoVec(libc::iovec {
++            iov_base: buf.as_ptr() as *mut c_void,
++            iov_len: buf.len() as size_t,
++        }, PhantomData)
++    }
++}
++
++impl<'a> IoVec<&'a mut [u8]> {
++    pub fn from_mut_slice(buf: &'a mut [u8]) -> IoVec<&'a mut [u8]> {
++        IoVec(libc::iovec {
++            iov_base: buf.as_ptr() as *mut c_void,
++            iov_len: buf.len() as size_t,
++        }, PhantomData)
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/utsname.rs b/third_party/rust/nix-0.15.0/src/sys/utsname.rs
+new file mode 100644
+index 0000000000000..ab09c7d23232a
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/utsname.rs
+@@ -0,0 +1,67 @@
++use std::mem;
++use libc::{self, c_char};
++use std::ffi::CStr;
++use std::str::from_utf8_unchecked;
++
++#[repr(C)]
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct UtsName(libc::utsname);
++
++impl UtsName {
++    pub fn sysname(&self) -> &str {
++        to_str(&(&self.0.sysname as *const c_char ) as *const *const c_char)
++    }
++
++    pub fn nodename(&self) -> &str {
++        to_str(&(&self.0.nodename as *const c_char ) as *const *const c_char)
++    }
++
++    pub fn release(&self) -> &str {
++        to_str(&(&self.0.release as *const c_char ) as *const *const c_char)
++    }
++
++    pub fn version(&self) -> &str {
++        to_str(&(&self.0.version as *const c_char ) as *const *const c_char)
++    }
++
++    pub fn machine(&self) -> &str {
++        to_str(&(&self.0.machine as *const c_char ) as *const *const c_char)
++    }
++}
++
++pub fn uname() -> UtsName {
++    unsafe {
++        let mut ret: UtsName = mem::uninitialized();
++        libc::uname(&mut ret.0);
++        ret
++    }
++}
++
++#[inline]
++fn to_str<'a>(s: *const *const c_char) -> &'a str {
++    unsafe {
++        let res = CStr::from_ptr(*s).to_bytes();
++        from_utf8_unchecked(res)
++    }
++}
++
++#[cfg(test)]
++mod test {
++    #[cfg(target_os = "linux")]
++    #[test]
++    pub fn test_uname_linux() {
++        assert_eq!(super::uname().sysname(), "Linux");
++    }
++
++    #[cfg(any(target_os = "macos", target_os = "ios"))]
++    #[test]
++    pub fn test_uname_darwin() {
++        assert_eq!(super::uname().sysname(), "Darwin");
++    }
++
++    #[cfg(target_os = "freebsd")]
++    #[test]
++    pub fn test_uname_freebsd() {
++        assert_eq!(super::uname().sysname(), "FreeBSD");
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/sys/wait.rs b/third_party/rust/nix-0.15.0/src/sys/wait.rs
+new file mode 100644
+index 0000000000000..c54f7ec579667
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/sys/wait.rs
+@@ -0,0 +1,239 @@
++use libc::{self, c_int};
++use Result;
++use errno::Errno;
++use unistd::Pid;
++
++use sys::signal::Signal;
++
++libc_bitflags!(
++    pub struct WaitPidFlag: c_int {
++        WNOHANG;
++        WUNTRACED;
++        #[cfg(any(target_os = "android",
++                  target_os = "freebsd",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos",
++                  target_os = "netbsd"))]
++        WEXITED;
++        WCONTINUED;
++        #[cfg(any(target_os = "android",
++                  target_os = "freebsd",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos",
++                  target_os = "netbsd"))]
++        WSTOPPED;
++        /// Don't reap, just poll status.
++        #[cfg(any(target_os = "android",
++                  target_os = "freebsd",
++                  target_os = "haiku",
++                  target_os = "ios",
++                  target_os = "linux",
++                  target_os = "macos",
++                  target_os = "netbsd"))]
++        WNOWAIT;
++        /// Don't wait on children of other threads in this group
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        __WNOTHREAD;
++        /// Wait on all children, regardless of type
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        __WALL;
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        __WCLONE;
++    }
++);
++
++/// Possible return values from `wait()` or `waitpid()`.
++///
++/// Each status (other than `StillAlive`) describes a state transition
++/// in a child process `Pid`, such as the process exiting or stopping,
++/// plus additional data about the transition if any.
++///
++/// Note that there are two Linux-specific enum variants, `PtraceEvent`
++/// and `PtraceSyscall`. Portable code should avoid exhaustively
++/// matching on `WaitStatus`.
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub enum WaitStatus {
++    /// The process exited normally (as with `exit()` or returning from
++    /// `main`) with the given exit code. This case matches the C macro
++    /// `WIFEXITED(status)`; the second field is `WEXITSTATUS(status)`.
++    Exited(Pid, i32),
++    /// The process was killed by the given signal. The third field
++    /// indicates whether the signal generated a core dump. This case
++    /// matches the C macro `WIFSIGNALED(status)`; the last two fields
++    /// correspond to `WTERMSIG(status)` and `WCOREDUMP(status)`.
++    Signaled(Pid, Signal, bool),
++    /// The process is alive, but was stopped by the given signal. This
++    /// is only reported if `WaitPidFlag::WUNTRACED` was passed. This
++    /// case matches the C macro `WIFSTOPPED(status)`; the second field
++    /// is `WSTOPSIG(status)`.
++    Stopped(Pid, Signal),
++    /// The traced process was stopped by a `PTRACE_EVENT_*` event. See
++    /// [`nix::sys::ptrace`] and [`ptrace`(2)] for more information. All
++    /// currently-defined events use `SIGTRAP` as the signal; the third
++    /// field is the `PTRACE_EVENT_*` value of the event.
++    ///
++    /// [`nix::sys::ptrace`]: ../ptrace/index.html
++    /// [`ptrace`(2)]: http://man7.org/linux/man-pages/man2/ptrace.2.html
++    #[cfg(any(target_os = "linux", target_os = "android"))]
++    PtraceEvent(Pid, Signal, c_int),
++    /// The traced process was stopped by execution of a system call,
++    /// and `PTRACE_O_TRACESYSGOOD` is in effect. See [`ptrace`(2)] for
++    /// more information.
++    ///
++    /// [`ptrace`(2)]: http://man7.org/linux/man-pages/man2/ptrace.2.html
++    #[cfg(any(target_os = "linux", target_os = "android"))]
++    PtraceSyscall(Pid),
++    /// The process was previously stopped but has resumed execution
++    /// after receiving a `SIGCONT` signal. This is only reported if
++    /// `WaitPidFlag::WCONTINUED` was passed. This case matches the C
++    /// macro `WIFCONTINUED(status)`.
++    Continued(Pid),
++    /// There are currently no state changes to report in any awaited
++    /// child process. This is only returned if `WaitPidFlag::WNOHANG`
++    /// was used (otherwise `wait()` or `waitpid()` would block until
++    /// there was something to report).
++    StillAlive,
++}
++
++impl WaitStatus {
++    /// Extracts the PID from the WaitStatus unless it equals StillAlive.
++    pub fn pid(&self) -> Option<Pid> {
++        use self::WaitStatus::*;
++        match *self {
++            Exited(p, _)  | Signaled(p, _, _) |
++                Stopped(p, _) | Continued(p) => Some(p),
++            StillAlive => None,
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            PtraceEvent(p, _, _) | PtraceSyscall(p) => Some(p),
++        }
++    }
++}
++
++fn exited(status: i32) -> bool {
++    unsafe { libc::WIFEXITED(status) }
++}
++
++fn exit_status(status: i32) -> i32 {
++    unsafe { libc::WEXITSTATUS(status) }
++}
++
++fn signaled(status: i32) -> bool {
++    unsafe { libc::WIFSIGNALED(status) }
++}
++
++fn term_signal(status: i32) -> Result<Signal> {
++    Signal::from_c_int(unsafe { libc::WTERMSIG(status) })
++}
++
++fn dumped_core(status: i32) -> bool {
++    unsafe { libc::WCOREDUMP(status) }
++}
++
++fn stopped(status: i32) -> bool {
++    unsafe { libc::WIFSTOPPED(status) }
++}
++
++fn stop_signal(status: i32) -> Result<Signal> {
++    Signal::from_c_int(unsafe { libc::WSTOPSIG(status) })
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn syscall_stop(status: i32) -> bool {
++    // From ptrace(2), setting PTRACE_O_TRACESYSGOOD has the effect
++    // of delivering SIGTRAP | 0x80 as the signal number for syscall
++    // stops. This allows easily distinguishing syscall stops from
++    // genuine SIGTRAP signals.
++    unsafe { libc::WSTOPSIG(status) == libc::SIGTRAP | 0x80 }
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn stop_additional(status: i32) -> c_int {
++    (status >> 16) as c_int
++}
++
++fn continued(status: i32) -> bool {
++    unsafe { libc::WIFCONTINUED(status) }
++}
++
++impl WaitStatus {
++    /// Convert a raw `wstatus` as returned by `waitpid`/`wait` into a `WaitStatus`
++    ///
++    /// # Errors
++    ///
++    /// Returns an `Error` corresponding to `EINVAL` for invalid status values.
++    ///
++    /// # Examples
++    ///
++    /// Convert a `wstatus` obtained from `libc::waitpid` into a `WaitStatus`:
++    ///
++    /// ```
++    /// use nix::sys::wait::WaitStatus;
++    /// use nix::sys::signal::Signal;
++    /// let pid = nix::unistd::Pid::from_raw(1);
++    /// let status = WaitStatus::from_raw(pid, 0x0002);
++    /// assert_eq!(status, Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false)));
++    /// ```
++    pub fn from_raw(pid: Pid, status: i32) -> Result<WaitStatus> {
++        Ok(if exited(status) {
++            WaitStatus::Exited(pid, exit_status(status))
++        } else if signaled(status) {
++            WaitStatus::Signaled(pid, term_signal(status)?, dumped_core(status))
++        } else if stopped(status) {
++            cfg_if! {
++                if #[cfg(any(target_os = "android", target_os = "linux"))] {
++                    fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> {
++                        let status_additional = stop_additional(status);
++                        Ok(if syscall_stop(status) {
++                            WaitStatus::PtraceSyscall(pid)
++                        } else if status_additional == 0 {
++                            WaitStatus::Stopped(pid, stop_signal(status)?)
++                        } else {
++                            WaitStatus::PtraceEvent(pid, stop_signal(status)?,
++                                                    stop_additional(status))
++                        })
++                    }
++                } else {
++                    fn decode_stopped(pid: Pid, status: i32) -> Result<WaitStatus> {
++                        Ok(WaitStatus::Stopped(pid, stop_signal(status)?))
++                    }
++                }
++            }
++            return decode_stopped(pid, status);
++        } else {
++            assert!(continued(status));
++            WaitStatus::Continued(pid)
++        })
++    }
++}
++
++pub fn waitpid<P: Into<Option<Pid>>>(pid: P, options: Option<WaitPidFlag>) -> Result<WaitStatus> {
++    use self::WaitStatus::*;
++
++    let mut status: i32 = 0;
++
++    let option_bits = match options {
++        Some(bits) => bits.bits(),
++        None => 0,
++    };
++
++    let res = unsafe {
++        libc::waitpid(
++            pid.into().unwrap_or(Pid::from_raw(-1)).into(),
++            &mut status as *mut c_int,
++            option_bits,
++        )
++    };
++
++    match Errno::result(res)? {
++        0 => Ok(StillAlive),
++        res => WaitStatus::from_raw(Pid::from_raw(res), status),
++    }
++}
++
++pub fn wait() -> Result<WaitStatus> {
++    waitpid(None, None)
++}
+diff --git a/third_party/rust/nix-0.15.0/src/ucontext.rs b/third_party/rust/nix-0.15.0/src/ucontext.rs
+new file mode 100644
+index 0000000000000..5e10e7d1f8934
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/ucontext.rs
+@@ -0,0 +1,39 @@
++use libc;
++#[cfg(not(target_env = "musl"))]
++use Result;
++#[cfg(not(target_env = "musl"))]
++use errno::Errno;
++use std::mem;
++use sys::signal::SigSet;
++
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++pub struct UContext {
++    context: libc::ucontext_t,
++}
++
++impl UContext {
++    #[cfg(not(target_env = "musl"))]
++    pub fn get() -> Result<UContext> {
++        let mut context: libc::ucontext_t = unsafe { mem::uninitialized() };
++        let res = unsafe {
++            libc::getcontext(&mut context as *mut libc::ucontext_t)
++        };
++        Errno::result(res).map(|_| UContext { context: context })
++    }
++
++    #[cfg(not(target_env = "musl"))]
++    pub fn set(&self) -> Result<()> {
++        let res = unsafe {
++            libc::setcontext(&self.context as *const libc::ucontext_t)
++        };
++        Errno::result(res).map(drop)
++    }
++
++    pub fn sigmask_mut(&mut self) -> &mut SigSet {
++        unsafe { mem::transmute(&mut self.context.uc_sigmask) }
++    }
++
++    pub fn sigmask(&self) -> &SigSet {
++        unsafe { mem::transmute(&self.context.uc_sigmask) }
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/src/unistd.rs b/third_party/rust/nix-0.15.0/src/unistd.rs
+new file mode 100644
+index 0000000000000..f422f09198655
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/src/unistd.rs
+@@ -0,0 +1,2394 @@
++//! Safe wrappers around functions found in libc "unistd.h" header
++
++use errno::{self, Errno};
++use {Error, Result, NixPath};
++use fcntl::{AtFlags, at_rawfd, fcntl, FdFlag, OFlag};
++use fcntl::FcntlArg::F_SETFD;
++use libc::{self, c_char, c_void, c_int, c_long, c_uint, size_t, pid_t, off_t,
++           uid_t, gid_t, mode_t};
++use std::{fmt, mem, ptr};
++use std::ffi::{CString, CStr, OsString, OsStr};
++use std::os::unix::ffi::{OsStringExt, OsStrExt};
++use std::os::unix::io::RawFd;
++use std::path::PathBuf;
++use void::Void;
++use sys::stat::Mode;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub use self::pivot_root::*;
++
++#[cfg(any(target_os = "android", target_os = "freebsd",
++          target_os = "linux", target_os = "openbsd"))]
++pub use self::setres::*;
++
++/// User identifier
++///
++/// Newtype pattern around `uid_t` (which is just alias). It prevents bugs caused by accidentally
++/// passing wrong value.
++#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
++pub struct Uid(uid_t);
++
++impl Uid {
++    /// Creates `Uid` from raw `uid_t`.
++    pub fn from_raw(uid: uid_t) -> Self {
++        Uid(uid)
++    }
++
++    /// Returns Uid of calling process. This is practically a more Rusty alias for `getuid`.
++    pub fn current() -> Self {
++        getuid()
++    }
++
++    /// Returns effective Uid of calling process. This is practically a more Rusty alias for `geteuid`.
++    pub fn effective() -> Self {
++        geteuid()
++    }
++
++    /// Returns true if the `Uid` represents privileged user - root. (If it equals zero.)
++    pub fn is_root(&self) -> bool {
++        *self == ROOT
++    }
++
++    /// Get the raw `uid_t` wrapped by `self`.
++    pub fn as_raw(&self) -> uid_t {
++        self.0
++    }
++}
++
++impl From<Uid> for uid_t {
++    fn from(uid: Uid) -> Self {
++        uid.0
++    }
++}
++
++impl fmt::Display for Uid {
++    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++        fmt::Display::fmt(&self.0, f)
++    }
++}
++
++/// Constant for UID = 0
++pub const ROOT: Uid = Uid(0);
++
++/// Group identifier
++///
++/// Newtype pattern around `gid_t` (which is just alias). It prevents bugs caused by accidentally
++/// passing wrong value.
++#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
++pub struct Gid(gid_t);
++
++impl Gid {
++    /// Creates `Gid` from raw `gid_t`.
++    pub fn from_raw(gid: gid_t) -> Self {
++        Gid(gid)
++    }
++
++    /// Returns Gid of calling process. This is practically a more Rusty alias for `getgid`.
++    pub fn current() -> Self {
++        getgid()
++    }
++
++    /// Returns effective Gid of calling process. This is practically a more Rusty alias for `getgid`.
++    pub fn effective() -> Self {
++        getegid()
++    }
++
++    /// Get the raw `gid_t` wrapped by `self`.
++    pub fn as_raw(&self) -> gid_t {
++        self.0
++    }
++}
++
++impl From<Gid> for gid_t {
++    fn from(gid: Gid) -> Self {
++        gid.0
++    }
++}
++
++impl fmt::Display for Gid {
++    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++        fmt::Display::fmt(&self.0, f)
++    }
++}
++
++/// Process identifier
++///
++/// Newtype pattern around `pid_t` (which is just alias). It prevents bugs caused by accidentally
++/// passing wrong value.
++#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
++pub struct Pid(pid_t);
++
++impl Pid {
++    /// Creates `Pid` from raw `pid_t`.
++    pub fn from_raw(pid: pid_t) -> Self {
++        Pid(pid)
++    }
++
++    /// Returns PID of calling process
++    pub fn this() -> Self {
++        getpid()
++    }
++
++    /// Returns PID of parent of calling process
++    pub fn parent() -> Self {
++        getppid()
++    }
++
++    /// Get the raw `pid_t` wrapped by `self`.
++    pub fn as_raw(&self) -> pid_t {
++        self.0
++    }
++}
++
++impl From<Pid> for pid_t {
++    fn from(pid: Pid) -> Self {
++        pid.0
++    }
++}
++
++impl fmt::Display for Pid {
++    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
++        fmt::Display::fmt(&self.0, f)
++    }
++}
++
++
++/// Represents the successful result of calling `fork`
++///
++/// When `fork` is called, the process continues execution in the parent process
++/// and in the new child.  This return type can be examined to determine whether
++/// you are now executing in the parent process or in the child.
++#[derive(Clone, Copy, Debug)]
++pub enum ForkResult {
++    Parent { child: Pid },
++    Child,
++}
++
++impl ForkResult {
++
++    /// Return `true` if this is the child process of the `fork()`
++    #[inline]
++    pub fn is_child(&self) -> bool {
++        match *self {
++            ForkResult::Child => true,
++            _ => false
++        }
++    }
++
++    /// Returns `true` if this is the parent process of the `fork()`
++    #[inline]
++    pub fn is_parent(&self) -> bool {
++        !self.is_child()
++    }
++}
++
++/// Create a new child process duplicating the parent process ([see
++/// fork(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html)).
++///
++/// After calling the fork system call (successfully) two processes will
++/// be created that are identical with the exception of their pid and the
++/// return value of this function.  As an example:
++///
++/// ```no_run
++/// use nix::unistd::{fork, ForkResult};
++///
++/// match fork() {
++///    Ok(ForkResult::Parent { child, .. }) => {
++///        println!("Continuing execution in parent process, new child has pid: {}", child);
++///    }
++///    Ok(ForkResult::Child) => println!("I'm a new child process"),
++///    Err(_) => println!("Fork failed"),
++/// }
++/// ```
++///
++/// This will print something like the following (order indeterministic).  The
++/// thing to note is that you end up with two processes continuing execution
++/// immediately after the fork call but with different match arms.
++///
++/// ```text
++/// Continuing execution in parent process, new child has pid: 1234
++/// I'm a new child process
++/// ```
++///
++/// # Safety
++///
++/// In a multithreaded program, only [async-signal-safe] functions like `pause`
++/// and `_exit` may be called by the child (the parent isn't restricted). Note
++/// that memory allocation may **not** be async-signal-safe and thus must be
++/// prevented.
++///
++/// Those functions are only a small subset of your operating system's API, so
++/// special care must be taken to only invoke code you can control and audit.
++///
++/// [async-signal-safe]: http://man7.org/linux/man-pages/man7/signal-safety.7.html
++#[inline]
++pub fn fork() -> Result<ForkResult> {
++    use self::ForkResult::*;
++    let res = unsafe { libc::fork() };
++
++    Errno::result(res).map(|res| match res {
++        0 => Child,
++        res => Parent { child: Pid(res) },
++    })
++}
++
++/// Get the pid of this process (see
++/// [getpid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpid.html)).
++///
++/// Since you are running code, there is always a pid to return, so there
++/// is no error case that needs to be handled.
++#[inline]
++pub fn getpid() -> Pid {
++    Pid(unsafe { libc::getpid() })
++}
++
++/// Get the pid of this processes' parent (see
++/// [getpid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getppid.html)).
++///
++/// There is always a parent pid to return, so there is no error case that needs
++/// to be handled.
++#[inline]
++pub fn getppid() -> Pid {
++    Pid(unsafe { libc::getppid() }) // no error handling, according to man page: "These functions are always successful."
++}
++
++/// Set a process group ID (see
++/// [setpgid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgid.html)).
++///
++/// Set the process group id (PGID) of a particular process.  If a pid of zero
++/// is specified, then the pid of the calling process is used.  Process groups
++/// may be used to group together a set of processes in order for the OS to
++/// apply some operations across the group.
++///
++/// `setsid()` may be used to create a new process group.
++#[inline]
++pub fn setpgid(pid: Pid, pgid: Pid) -> Result<()> {
++    let res = unsafe { libc::setpgid(pid.into(), pgid.into()) };
++    Errno::result(res).map(drop)
++}
++#[inline]
++pub fn getpgid(pid: Option<Pid>) -> Result<Pid> {
++    let res = unsafe { libc::getpgid(pid.unwrap_or(Pid(0)).into()) };
++    Errno::result(res).map(Pid)
++}
++
++/// Create new session and set process group id (see
++/// [setsid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsid.html)).
++#[inline]
++pub fn setsid() -> Result<Pid> {
++    Errno::result(unsafe { libc::setsid() }).map(Pid)
++}
++
++/// Get the process group ID of a session leader
++/// [getsid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsid.html).
++///
++/// Obtain the process group ID of the process that is the session leader of the process specified
++/// by pid. If pid is zero, it specifies the calling process.
++#[inline]
++pub fn getsid(pid: Option<Pid>) -> Result<Pid> {
++    let res = unsafe { libc::getsid(pid.unwrap_or(Pid(0)).into()) };
++    Errno::result(res).map(Pid)
++}
++
++
++/// Get the terminal foreground process group (see
++/// [tcgetpgrp(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetpgrp.html)).
++///
++/// Get the group process id (GPID) of the foreground process group on the
++/// terminal associated to file descriptor (FD).
++#[inline]
++pub fn tcgetpgrp(fd: c_int) -> Result<Pid> {
++    let res = unsafe { libc::tcgetpgrp(fd) };
++    Errno::result(res).map(Pid)
++}
++/// Set the terminal foreground process group (see
++/// [tcgetpgrp(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetpgrp.html)).
++///
++/// Get the group process id (PGID) to the foreground process group on the
++/// terminal associated to file descriptor (FD).
++#[inline]
++pub fn tcsetpgrp(fd: c_int, pgrp: Pid) -> Result<()> {
++    let res = unsafe { libc::tcsetpgrp(fd, pgrp.into()) };
++    Errno::result(res).map(drop)
++}
++
++
++/// Get the group id of the calling process (see
++///[getpgrp(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgrp.html)).
++///
++/// Get the process group id (PGID) of the calling process.
++/// According to the man page it is always successful.
++#[inline]
++pub fn getpgrp() -> Pid {
++    Pid(unsafe { libc::getpgrp() })
++}
++
++/// Get the caller's thread ID (see
++/// [gettid(2)](http://man7.org/linux/man-pages/man2/gettid.2.html).
++///
++/// This function is only available on Linux based systems.  In a single
++/// threaded process, the main thread will have the same ID as the process.  In
++/// a multithreaded process, each thread will have a unique thread id but the
++/// same process ID.
++///
++/// No error handling is required as a thread id should always exist for any
++/// process, even if threads are not being used.
++#[cfg(any(target_os = "linux", target_os = "android"))]
++#[inline]
++pub fn gettid() -> Pid {
++    Pid(unsafe { libc::syscall(libc::SYS_gettid) as pid_t })
++}
++
++/// Create a copy of the specified file descriptor (see
++/// [dup(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)).
++///
++/// The new file descriptor will be have a new index but refer to the same
++/// resource as the old file descriptor and the old and new file descriptors may
++/// be used interchangeably.  The new and old file descriptor share the same
++/// underlying resource, offset, and file status flags.  The actual index used
++/// for the file descriptor will be the lowest fd index that is available.
++///
++/// The two file descriptors do not share file descriptor flags (e.g. `OFlag::FD_CLOEXEC`).
++#[inline]
++pub fn dup(oldfd: RawFd) -> Result<RawFd> {
++    let res = unsafe { libc::dup(oldfd) };
++
++    Errno::result(res)
++}
++
++/// Create a copy of the specified file descriptor using the specified fd (see
++/// [dup(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)).
++///
++/// This function behaves similar to `dup()` except that it will try to use the
++/// specified fd instead of allocating a new one.  See the man pages for more
++/// detail on the exact behavior of this function.
++#[inline]
++pub fn dup2(oldfd: RawFd, newfd: RawFd) -> Result<RawFd> {
++    let res = unsafe { libc::dup2(oldfd, newfd) };
++
++    Errno::result(res)
++}
++
++/// Create a new copy of the specified file descriptor using the specified fd
++/// and flags (see [dup(2)](http://man7.org/linux/man-pages/man2/dup.2.html)).
++///
++/// This function behaves similar to `dup2()` but allows for flags to be
++/// specified.
++pub fn dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
++    dup3_polyfill(oldfd, newfd, flags)
++}
++
++#[inline]
++fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
++    if oldfd == newfd {
++        return Err(Error::Sys(Errno::EINVAL));
++    }
++
++    let fd = dup2(oldfd, newfd)?;
++
++    if flags.contains(OFlag::O_CLOEXEC) {
++        if let Err(e) = fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC)) {
++            let _ = close(fd);
++            return Err(e);
++        }
++    }
++
++    Ok(fd)
++}
++
++/// Change the current working directory of the calling process (see
++/// [chdir(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/chdir.html)).
++///
++/// This function may fail in a number of different scenarios.  See the man
++/// pages for additional details on possible failure cases.
++#[inline]
++pub fn chdir<P: ?Sized + NixPath>(path: &P) -> Result<()> {
++    let res = path.with_nix_path(|cstr| {
++        unsafe { libc::chdir(cstr.as_ptr()) }
++    })?;
++
++    Errno::result(res).map(drop)
++}
++
++/// Change the current working directory of the process to the one
++/// given as an open file descriptor (see
++/// [fchdir(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchdir.html)).
++///
++/// This function may fail in a number of different scenarios.  See the man
++/// pages for additional details on possible failure cases.
++#[inline]
++pub fn fchdir(dirfd: RawFd) -> Result<()> {
++    let res = unsafe { libc::fchdir(dirfd) };
++
++    Errno::result(res).map(drop)
++}
++
++/// Creates new directory `path` with access rights `mode`.  (see [mkdir(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html))
++///
++/// # Errors
++///
++/// There are several situations where mkdir might fail:
++///
++/// - current user has insufficient rights in the parent directory
++/// - the path already exists
++/// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X)
++///
++/// # Example
++///
++/// ```rust
++/// extern crate tempfile;
++/// extern crate nix;
++///
++/// use nix::unistd;
++/// use nix::sys::stat;
++/// use tempfile::tempdir;
++///
++/// fn main() {
++///     let tmp_dir1 = tempdir().unwrap();
++///     let tmp_dir2 = tmp_dir1.path().join("new_dir");
++///
++///     // create new directory and give read, write and execute rights to the owner
++///     match unistd::mkdir(&tmp_dir2, stat::Mode::S_IRWXU) {
++///        Ok(_) => println!("created {:?}", tmp_dir2),
++///        Err(err) => println!("Error creating directory: {}", err),
++///     }
++/// }
++/// ```
++#[inline]
++pub fn mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
++    let res = path.with_nix_path(|cstr| {
++        unsafe { libc::mkdir(cstr.as_ptr(), mode.bits() as mode_t) }
++    })?;
++
++    Errno::result(res).map(drop)
++}
++
++/// Creates new fifo special file (named pipe) with path `path` and access rights `mode`.
++///
++/// # Errors
++///
++/// There are several situations where mkfifo might fail:
++///
++/// - current user has insufficient rights in the parent directory
++/// - the path already exists
++/// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X)
++///
++/// For a full list consult
++/// [posix specification](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifo.html)
++///
++/// # Example
++///
++/// ```rust
++/// extern crate tempfile;
++/// extern crate nix;
++///
++/// use nix::unistd;
++/// use nix::sys::stat;
++/// use tempfile::tempdir;
++///
++/// fn main() {
++///     let tmp_dir = tempdir().unwrap();
++///     let fifo_path = tmp_dir.path().join("foo.pipe");
++///
++///     // create new fifo and give read, write and execute rights to the owner
++///     match unistd::mkfifo(&fifo_path, stat::Mode::S_IRWXU) {
++///        Ok(_) => println!("created {:?}", fifo_path),
++///        Err(err) => println!("Error creating fifo: {}", err),
++///     }
++/// }
++/// ```
++#[inline]
++pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
++    let res = path.with_nix_path(|cstr| {
++        unsafe { libc::mkfifo(cstr.as_ptr(), mode.bits() as mode_t) }
++    })?;
++
++    Errno::result(res).map(drop)
++}
++
++/// Creates a symbolic link at `path2` which points to `path1`.
++///
++/// If `dirfd` has a value, then `path2` is relative to directory associated
++/// with the file descriptor.
++///
++/// If `dirfd` is `None`, then `path2` is relative to the current working
++/// directory. This is identical to `libc::symlink(path1, path2)`.
++///
++/// See also [symlinkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html).
++pub fn symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
++    path1: &P1,
++    dirfd: Option<RawFd>,
++    path2: &P2) -> Result<()> {
++    let res =
++        path1.with_nix_path(|path1| {
++            path2.with_nix_path(|path2| {
++                unsafe {
++                    libc::symlinkat(
++                        path1.as_ptr(),
++                        dirfd.unwrap_or(libc::AT_FDCWD),
++                        path2.as_ptr()
++                    )
++                }
++            })
++        })??;
++    Errno::result(res).map(drop)
++}
++
++/// Returns the current directory as a `PathBuf`
++///
++/// Err is returned if the current user doesn't have the permission to read or search a component
++/// of the current path.
++///
++/// # Example
++///
++/// ```rust
++/// extern crate nix;
++///
++/// use nix::unistd;
++///
++/// fn main() {
++///     // assume that we are allowed to get current directory
++///     let dir = unistd::getcwd().unwrap();
++///     println!("The current directory is {:?}", dir);
++/// }
++/// ```
++#[inline]
++pub fn getcwd() -> Result<PathBuf> {
++    let mut buf = Vec::with_capacity(512);
++    loop {
++        unsafe {
++            let ptr = buf.as_mut_ptr() as *mut c_char;
++
++            // The buffer must be large enough to store the absolute pathname plus
++            // a terminating null byte, or else null is returned.
++            // To safely handle this we start with a reasonable size (512 bytes)
++            // and double the buffer size upon every error
++            if !libc::getcwd(ptr, buf.capacity()).is_null() {
++                let len = CStr::from_ptr(buf.as_ptr() as *const c_char).to_bytes().len();
++                buf.set_len(len);
++                buf.shrink_to_fit();
++                return Ok(PathBuf::from(OsString::from_vec(buf)));
++            } else {
++                let error = Errno::last();
++                // ERANGE means buffer was too small to store directory name
++                if error != Errno::ERANGE {
++                    return Err(Error::Sys(error));
++                }
++            }
++
++            // Trigger the internal buffer resizing logic of `Vec` by requiring
++            // more space than the current capacity.
++            let cap = buf.capacity();
++            buf.set_len(cap);
++            buf.reserve(1);
++        }
++    }
++}
++
++/// Computes the raw UID and GID values to pass to a `*chown` call.
++fn chown_raw_ids(owner: Option<Uid>, group: Option<Gid>) -> (libc::uid_t, libc::gid_t) {
++    // According to the POSIX specification, -1 is used to indicate that owner and group
++    // are not to be changed.  Since uid_t and gid_t are unsigned types, we have to wrap
++    // around to get -1.
++    let uid = owner.map(Into::into).unwrap_or((0 as uid_t).wrapping_sub(1));
++    let gid = group.map(Into::into).unwrap_or((0 as gid_t).wrapping_sub(1));
++    (uid, gid)
++}
++
++/// Change the ownership of the file at `path` to be owned by the specified
++/// `owner` (user) and `group` (see
++/// [chown(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html)).
++///
++/// The owner/group for the provided path name will not be modified if `None` is
++/// provided for that argument.  Ownership change will be attempted for the path
++/// only if `Some` owner/group is provided.
++#[inline]
++pub fn chown<P: ?Sized + NixPath>(path: &P, owner: Option<Uid>, group: Option<Gid>) -> Result<()> {
++    let res = path.with_nix_path(|cstr| {
++        let (uid, gid) = chown_raw_ids(owner, group);
++        unsafe { libc::chown(cstr.as_ptr(), uid, gid) }
++    })?;
++
++    Errno::result(res).map(drop)
++}
++
++/// Flags for `fchownat` function.
++#[derive(Clone, Copy, Debug)]
++pub enum FchownatFlags {
++    FollowSymlink,
++    NoFollowSymlink,
++}
++
++/// Change the ownership of the file at `path` to be owned by the specified
++/// `owner` (user) and `group`.
++///
++/// The owner/group for the provided path name will not be modified if `None` is
++/// provided for that argument.  Ownership change will be attempted for the path
++/// only if `Some` owner/group is provided.
++///
++/// The file to be changed is determined relative to the directory associated
++/// with the file descriptor `dirfd` or the current working directory
++/// if `dirfd` is `None`.
++///
++/// If `flag` is `FchownatFlags::NoFollowSymlink` and `path` names a symbolic link,
++/// then the mode of the symbolic link is changed.
++///
++/// `fchownat(None, path, mode, FchownatFlags::NoFollowSymlink)` is identical to
++/// a call `libc::lchown(path, mode)`.  That's why `lchmod` is unimplemented in
++/// the `nix` crate.
++///
++/// # References
++///
++/// [fchownat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchownat.html).
++pub fn fchownat<P: ?Sized + NixPath>(
++    dirfd: Option<RawFd>,
++    path: &P,
++    owner: Option<Uid>,
++    group: Option<Gid>,
++    flag: FchownatFlags,
++) -> Result<()> {
++    let atflag =
++        match flag {
++            FchownatFlags::FollowSymlink => AtFlags::empty(),
++            FchownatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
++        };
++    let res = path.with_nix_path(|cstr| unsafe {
++        let (uid, gid) = chown_raw_ids(owner, group);
++        libc::fchownat(at_rawfd(dirfd), cstr.as_ptr(), uid, gid,
++                       atflag.bits() as libc::c_int)
++    })?;
++
++    Errno::result(res).map(drop)
++}
++
++fn to_exec_array(args: &[CString]) -> Vec<*const c_char> {
++    let mut args_p: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect();
++    args_p.push(ptr::null());
++    args_p
++}
++
++/// Replace the current process image with a new one (see
++/// [exec(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)).
++///
++/// See the `::nix::unistd::execve` system call for additional details.  `execv`
++/// performs the same action but does not allow for customization of the
++/// environment for the new process.
++#[inline]
++pub fn execv(path: &CString, argv: &[CString]) -> Result<Void> {
++    let args_p = to_exec_array(argv);
++
++    unsafe {
++        libc::execv(path.as_ptr(), args_p.as_ptr())
++    };
++
++    Err(Error::Sys(Errno::last()))
++}
++
++
++/// Replace the current process image with a new one (see
++/// [execve(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)).
++///
++/// The execve system call allows for another process to be "called" which will
++/// replace the current process image.  That is, this process becomes the new
++/// command that is run. On success, this function will not return. Instead,
++/// the new program will run until it exits.
++///
++/// `::nix::unistd::execv` and `::nix::unistd::execve` take as arguments a slice
++/// of `::std::ffi::CString`s for `args` and `env` (for `execve`). Each element
++/// in the `args` list is an argument to the new process. Each element in the
++/// `env` list should be a string in the form "key=value".
++#[inline]
++pub fn execve(path: &CString, args: &[CString], env: &[CString]) -> Result<Void> {
++    let args_p = to_exec_array(args);
++    let env_p = to_exec_array(env);
++
++    unsafe {
++        libc::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
++    };
++
++    Err(Error::Sys(Errno::last()))
++}
++
++/// Replace the current process image with a new one and replicate shell `PATH`
++/// searching behavior (see
++/// [exec(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)).
++///
++/// See `::nix::unistd::execve` for additional details.  `execvp` behaves the
++/// same as execv except that it will examine the `PATH` environment variables
++/// for file names not specified with a leading slash.  For example, `execv`
++/// would not work if "bash" was specified for the path argument, but `execvp`
++/// would assuming that a bash executable was on the system `PATH`.
++#[inline]
++pub fn execvp(filename: &CString, args: &[CString]) -> Result<Void> {
++    let args_p = to_exec_array(args);
++
++    unsafe {
++        libc::execvp(filename.as_ptr(), args_p.as_ptr())
++    };
++
++    Err(Error::Sys(Errno::last()))
++}
++
++/// Replace the current process image with a new one and replicate shell `PATH`
++/// searching behavior (see
++/// [`execvpe(3)`](http://man7.org/linux/man-pages/man3/exec.3.html)).
++///
++/// This functions like a combination of `execvp(2)` and `execve(2)` to pass an
++/// environment and have a search path. See these two for additional
++/// information.
++#[cfg(any(target_os = "haiku",
++          target_os = "linux",
++          target_os = "openbsd"))]
++pub fn execvpe(filename: &CString, args: &[CString], env: &[CString]) -> Result<Void> {
++    let args_p = to_exec_array(args);
++    let env_p = to_exec_array(env);
++
++    unsafe {
++        libc::execvpe(filename.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
++    };
++
++    Err(Error::Sys(Errno::last()))
++}
++
++/// Replace the current process image with a new one (see
++/// [fexecve(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html)).
++///
++/// The `fexecve` function allows for another process to be "called" which will
++/// replace the current process image.  That is, this process becomes the new
++/// command that is run. On success, this function will not return. Instead,
++/// the new program will run until it exits.
++///
++/// This function is similar to `execve`, except that the program to be executed
++/// is referenced as a file descriptor instead of a path.
++// Note for NetBSD and OpenBSD: although rust-lang/libc includes it (under
++// unix/bsd/netbsdlike/) fexecve is not currently implemented on NetBSD nor on
++// OpenBSD.
++#[cfg(any(target_os = "android",
++          target_os = "linux",
++          target_os = "freebsd"))]
++#[inline]
++pub fn fexecve(fd: RawFd, args: &[CString], env: &[CString]) -> Result<Void> {
++    let args_p = to_exec_array(args);
++    let env_p = to_exec_array(env);
++
++    unsafe {
++        libc::fexecve(fd, args_p.as_ptr(), env_p.as_ptr())
++    };
++
++    Err(Error::Sys(Errno::last()))
++}
++
++/// Execute program relative to a directory file descriptor (see
++/// [execveat(2)](http://man7.org/linux/man-pages/man2/execveat.2.html)).
++///
++/// The `execveat` function allows for another process to be "called" which will
++/// replace the current process image.  That is, this process becomes the new
++/// command that is run. On success, this function will not return. Instead,
++/// the new program will run until it exits.
++///
++/// This function is similar to `execve`, except that the program to be executed
++/// is referenced as a file descriptor to the base directory plus a path.
++#[cfg(any(target_os = "android", target_os = "linux"))]
++#[inline]
++pub fn execveat(dirfd: RawFd, pathname: &CString, args: &[CString],
++                env: &[CString], flags: super::fcntl::AtFlags) -> Result<Void> {
++    let args_p = to_exec_array(args);
++    let env_p = to_exec_array(env);
++
++    unsafe {
++        libc::syscall(libc::SYS_execveat, dirfd, pathname.as_ptr(),
++                      args_p.as_ptr(), env_p.as_ptr(), flags);
++    };
++
++    Err(Error::Sys(Errno::last()))
++}
++
++/// Daemonize this process by detaching from the controlling terminal (see
++/// [daemon(3)](http://man7.org/linux/man-pages/man3/daemon.3.html)).
++///
++/// When a process is launched it is typically associated with a parent and it,
++/// in turn, by its controlling terminal/process.  In order for a process to run
++/// in the "background" it must daemonize itself by detaching itself.  Under
++/// posix, this is done by doing the following:
++///
++/// 1. Parent process (this one) forks
++/// 2. Parent process exits
++/// 3. Child process continues to run.
++///
++/// `nochdir`:
++///
++/// * `nochdir = true`: The current working directory after daemonizing will
++///    be the current working directory.
++/// *  `nochdir = false`: The current working directory after daemonizing will
++///    be the root direcory, `/`.
++///
++/// `noclose`:
++///
++/// * `noclose = true`: The process' current stdin, stdout, and stderr file
++///   descriptors will remain identical after daemonizing.
++/// * `noclose = false`: The process' stdin, stdout, and stderr will point to
++///   `/dev/null` after daemonizing.
++#[cfg_attr(any(target_os = "macos", target_os = "ios"), deprecated(
++    since="0.14.0",
++    note="Deprecated in MacOSX 10.5"
++))]
++#[cfg_attr(any(target_os = "macos", target_os = "ios"), allow(deprecated))]
++pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> {
++    let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) };
++    Errno::result(res).map(drop)
++}
++
++/// Set the system host name (see
++/// [sethostname(2)](http://man7.org/linux/man-pages/man2/gethostname.2.html)).
++///
++/// Given a name, attempt to update the system host name to the given string.
++/// On some systems, the host name is limited to as few as 64 bytes.  An error
++/// will be return if the name is not valid or the current process does not have
++/// permissions to update the host name.
++pub fn sethostname<S: AsRef<OsStr>>(name: S) -> Result<()> {
++    // Handle some differences in type of the len arg across platforms.
++    cfg_if! {
++        if #[cfg(any(target_os = "dragonfly",
++                     target_os = "freebsd",
++                     target_os = "ios",
++                     target_os = "macos", ))] {
++            type sethostname_len_t = c_int;
++        } else {
++            type sethostname_len_t = size_t;
++        }
++    }
++    let ptr = name.as_ref().as_bytes().as_ptr() as *const c_char;
++    let len = name.as_ref().len() as sethostname_len_t;
++
++    let res = unsafe { libc::sethostname(ptr, len) };
++    Errno::result(res).map(drop)
++}
++
++/// Get the host name and store it in the provided buffer, returning a pointer
++/// the `CStr` in that buffer on success (see
++/// [gethostname(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/gethostname.html)).
++///
++/// This function call attempts to get the host name for the running system and
++/// store it in a provided buffer.  The buffer will be populated with bytes up
++/// to the length of the provided slice including a NUL terminating byte.  If
++/// the hostname is longer than the length provided, no error will be provided.
++/// The posix specification does not specify whether implementations will
++/// null-terminate in this case, but the nix implementation will ensure that the
++/// buffer is null terminated in this case.
++///
++/// ```no_run
++/// use nix::unistd;
++///
++/// let mut buf = [0u8; 64];
++/// let hostname_cstr = unistd::gethostname(&mut buf).expect("Failed getting hostname");
++/// let hostname = hostname_cstr.to_str().expect("Hostname wasn't valid UTF-8");
++/// println!("Hostname: {}", hostname);
++/// ```
++pub fn gethostname(buffer: &mut [u8]) -> Result<&CStr> {
++    let ptr = buffer.as_mut_ptr() as *mut c_char;
++    let len = buffer.len() as size_t;
++
++    let res = unsafe { libc::gethostname(ptr, len) };
++    Errno::result(res).map(|_| {
++        buffer[len - 1] = 0; // ensure always null-terminated
++        unsafe { CStr::from_ptr(buffer.as_ptr() as *const c_char) }
++    })
++}
++
++/// Close a raw file descriptor
++///
++/// Be aware that many Rust types implicitly close-on-drop, including
++/// `std::fs::File`.  Explicitly closing them with this method too can result in
++/// a double-close condition, which can cause confusing `EBADF` errors in
++/// seemingly unrelated code.  Caveat programmer.  See also
++/// [close(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html).
++///
++/// # Examples
++///
++/// ```no_run
++/// extern crate tempfile;
++/// extern crate nix;
++///
++/// use std::os::unix::io::AsRawFd;
++/// use nix::unistd::close;
++///
++/// fn main() {
++///     let f = tempfile::tempfile().unwrap();
++///     close(f.as_raw_fd()).unwrap();   // Bad!  f will also close on drop!
++/// }
++/// ```
++///
++/// ```rust
++/// extern crate tempfile;
++/// extern crate nix;
++///
++/// use std::os::unix::io::IntoRawFd;
++/// use nix::unistd::close;
++///
++/// fn main() {
++///     let f = tempfile::tempfile().unwrap();
++///     close(f.into_raw_fd()).unwrap(); // Good.  into_raw_fd consumes f
++/// }
++/// ```
++pub fn close(fd: RawFd) -> Result<()> {
++    let res = unsafe { libc::close(fd) };
++    Errno::result(res).map(drop)
++}
++
++/// Read from a raw file descriptor.
++///
++/// See also [read(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html)
++pub fn read(fd: RawFd, buf: &mut [u8]) -> Result<usize> {
++    let res = unsafe { libc::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t) };
++
++    Errno::result(res).map(|r| r as usize)
++}
++
++/// Write to a raw file descriptor.
++///
++/// See also [write(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html)
++pub fn write(fd: RawFd, buf: &[u8]) -> Result<usize> {
++    let res = unsafe { libc::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t) };
++
++    Errno::result(res).map(|r| r as usize)
++}
++
++/// Directive that tells [`lseek`] and [`lseek64`] what the offset is relative to.
++///
++/// [`lseek`]: ./fn.lseek.html
++/// [`lseek64`]: ./fn.lseek64.html
++#[repr(i32)]
++#[derive(Clone, Copy, Debug)]
++pub enum Whence {
++    /// Specify an offset relative to the start of the file.
++    SeekSet = libc::SEEK_SET,
++    /// Specify an offset relative to the current file location.
++    SeekCur = libc::SEEK_CUR,
++    /// Specify an offset relative to the end of the file.
++    SeekEnd = libc::SEEK_END,
++    /// Specify an offset relative to the next location in the file greater than or
++    /// equal to offset that contains some data. If offset points to
++    /// some data, then the file offset is set to offset.
++    #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
++          all(target_os = "linux", not(any(target_env = "musl",
++                                           target_arch = "mips",
++                                           target_arch = "mips64")))))]
++    SeekData = libc::SEEK_DATA,
++    /// Specify an offset relative to the next hole in the file greater than
++    /// or equal to offset. If offset points into the middle of a hole, then
++    /// the file offset should be set to offset. If there is no hole past offset,
++    /// then the file offset should be adjusted to the end of the file (i.e., there
++    /// is an implicit hole at the end of any file).
++    #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
++          all(target_os = "linux", not(any(target_env = "musl",
++                                           target_arch = "mips",
++                                           target_arch = "mips64")))))]
++    SeekHole = libc::SEEK_HOLE
++}
++
++/// Move the read/write file offset.
++///
++/// See also [lseek(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lseek.html)
++pub fn lseek(fd: RawFd, offset: off_t, whence: Whence) -> Result<off_t> {
++    let res = unsafe { libc::lseek(fd, offset, whence as i32) };
++
++    Errno::result(res).map(|r| r as off_t)
++}
++
++#[cfg(any(target_os = "linux", target_os = "android"))]
++pub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result<libc::off64_t> {
++    let res = unsafe { libc::lseek64(fd, offset, whence as i32) };
++
++    Errno::result(res).map(|r| r as libc::off64_t)
++}
++
++/// Create an interprocess channel.
++///
++/// See also [pipe(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html)
++pub fn pipe() -> Result<(RawFd, RawFd)> {
++    unsafe {
++        let mut fds: [c_int; 2] = mem::uninitialized();
++
++        let res = libc::pipe(fds.as_mut_ptr());
++
++        Errno::result(res)?;
++
++        Ok((fds[0], fds[1]))
++    }
++}
++
++/// Like `pipe`, but allows setting certain file descriptor flags.
++///
++/// The following flags are supported, and will be set atomically as the pipe is
++/// created:
++///
++/// `O_CLOEXEC`:    Set the close-on-exec flag for the new file descriptors.
++/// `O_NONBLOCK`:   Set the non-blocking flag for the ends of the pipe.
++///
++/// See also [pipe(2)](http://man7.org/linux/man-pages/man2/pipe.2.html)
++#[cfg(any(target_os = "android",
++          target_os = "dragonfly",
++          target_os = "emscripten",
++          target_os = "freebsd",
++          target_os = "linux",
++          target_os = "netbsd",
++          target_os = "openbsd"))]
++pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
++    let mut fds: [c_int; 2] = unsafe { mem::uninitialized() };
++
++    let res = unsafe { libc::pipe2(fds.as_mut_ptr(), flags.bits()) };
++
++    Errno::result(res)?;
++
++    Ok((fds[0], fds[1]))
++}
++
++/// Like `pipe`, but allows setting certain file descriptor flags.
++///
++/// The following flags are supported, and will be set after the pipe is
++/// created:
++///
++/// `O_CLOEXEC`:    Set the close-on-exec flag for the new file descriptors.
++/// `O_NONBLOCK`:   Set the non-blocking flag for the ends of the pipe.
++#[cfg(any(target_os = "ios", target_os = "macos"))]
++#[deprecated(
++    since="0.10.0",
++    note="pipe2(2) is not actually atomic on these platforms.  Use pipe(2) and fcntl(2) instead"
++)]
++pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
++    let mut fds: [c_int; 2] = unsafe { mem::uninitialized() };
++
++    let res = unsafe { libc::pipe(fds.as_mut_ptr()) };
++
++    Errno::result(res)?;
++
++    pipe2_setflags(fds[0], fds[1], flags)?;
++
++    Ok((fds[0], fds[1]))
++}
++
++#[cfg(any(target_os = "ios", target_os = "macos"))]
++fn pipe2_setflags(fd1: RawFd, fd2: RawFd, flags: OFlag) -> Result<()> {
++    use fcntl::FcntlArg::F_SETFL;
++
++    let mut res = Ok(0);
++
++    if flags.contains(OFlag::O_CLOEXEC) {
++        res = res
++            .and_then(|_| fcntl(fd1, F_SETFD(FdFlag::FD_CLOEXEC)))
++            .and_then(|_| fcntl(fd2, F_SETFD(FdFlag::FD_CLOEXEC)));
++    }
++
++    if flags.contains(OFlag::O_NONBLOCK) {
++        res = res
++            .and_then(|_| fcntl(fd1, F_SETFL(OFlag::O_NONBLOCK)))
++            .and_then(|_| fcntl(fd2, F_SETFL(OFlag::O_NONBLOCK)));
++    }
++
++    match res {
++        Ok(_) => Ok(()),
++        Err(e) => {
++            let _ = close(fd1);
++            let _ = close(fd2);
++            Err(e)
++        }
++    }
++}
++
++/// Truncate a file to a specified length
++///
++/// See also
++/// [truncate(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html)
++pub fn truncate<P: ?Sized + NixPath>(path: &P, len: off_t) -> Result<()> {
++    let res = path.with_nix_path(|cstr| {
++        unsafe {
++            libc::truncate(cstr.as_ptr(), len)
++        }
++    })?;
++
++    Errno::result(res).map(drop)
++}
++
++/// Truncate a file to a specified length
++///
++/// See also
++/// [ftruncate(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html)
++pub fn ftruncate(fd: RawFd, len: off_t) -> Result<()> {
++    Errno::result(unsafe { libc::ftruncate(fd, len) }).map(drop)
++}
++
++pub fn isatty(fd: RawFd) -> Result<bool> {
++    unsafe {
++        // ENOTTY means `fd` is a valid file descriptor, but not a TTY, so
++        // we return `Ok(false)`
++        if libc::isatty(fd) == 1 {
++            Ok(true)
++        } else {
++            match Errno::last() {
++                Errno::ENOTTY => Ok(false),
++                err => Err(Error::Sys(err)),
++            }
++        }
++    }
++}
++
++/// Remove a directory entry
++///
++/// See also [unlink(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html)
++pub fn unlink<P: ?Sized + NixPath>(path: &P) -> Result<()> {
++    let res = path.with_nix_path(|cstr| {
++        unsafe {
++            libc::unlink(cstr.as_ptr())
++        }
++    })?;
++    Errno::result(res).map(drop)
++}
++
++/// Flags for `unlinkat` function.
++#[derive(Clone, Copy, Debug)]
++pub enum UnlinkatFlags {
++    RemoveDir,
++    NoRemoveDir,
++}
++
++/// Remove a directory entry
++///
++/// In the case of a relative path, the directory entry to be removed is determined relative to
++/// the directory associated with the file descriptor `dirfd` or the current working directory
++/// if `dirfd` is `None`. In the case of an absolute `path` `dirfd` is ignored. If `flag` is
++/// `UnlinkatFlags::RemoveDir` then removal of the directory entry specified by `dirfd` and `path`
++/// is performed.
++///
++/// # References
++/// See also [unlinkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/unlinkat.html)
++pub fn unlinkat<P: ?Sized + NixPath>(
++    dirfd: Option<RawFd>,
++    path: &P,
++    flag: UnlinkatFlags,
++) -> Result<()> {
++    let atflag =
++        match flag {
++            UnlinkatFlags::RemoveDir => AtFlags::AT_REMOVEDIR,
++            UnlinkatFlags::NoRemoveDir => AtFlags::empty(),
++        };
++    let res = path.with_nix_path(|cstr| {
++        unsafe {
++            libc::unlinkat(at_rawfd(dirfd), cstr.as_ptr(), atflag.bits() as libc::c_int)
++        }
++    })?;
++    Errno::result(res).map(drop)
++}
++
++
++#[inline]
++pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> {
++    let res = path.with_nix_path(|cstr| {
++        unsafe { libc::chroot(cstr.as_ptr()) }
++    })?;
++
++    Errno::result(res).map(drop)
++}
++
++/// Commit filesystem caches to disk
++///
++/// See also [sync(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sync.html)
++#[cfg(any(
++    target_os = "dragonfly",
++    target_os = "freebsd",
++    target_os = "linux",
++    target_os = "netbsd",
++    target_os = "openbsd"
++))]
++pub fn sync() -> () {
++    unsafe { libc::sync() };
++}
++
++/// Synchronize changes to a file
++///
++/// See also [fsync(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html)
++#[inline]
++pub fn fsync(fd: RawFd) -> Result<()> {
++    let res = unsafe { libc::fsync(fd) };
++
++    Errno::result(res).map(drop)
++}
++
++/// Synchronize the data of a file
++///
++/// See also
++/// [fdatasync(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html)
++// `fdatasync(2) is in POSIX, but in libc it is only defined in `libc::notbsd`.
++// TODO: exclude only Apple systems after https://github.com/rust-lang/libc/pull/211
++#[cfg(any(target_os = "linux",
++          target_os = "android",
++          target_os = "emscripten"))]
++#[inline]
++pub fn fdatasync(fd: RawFd) -> Result<()> {
++    let res = unsafe { libc::fdatasync(fd) };
++
++    Errno::result(res).map(drop)
++}
++
++/// Get a real user ID
++///
++/// See also [getuid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getuid.html)
++// POSIX requires that getuid is always successful, so no need to check return
++// value or errno.
++#[inline]
++pub fn getuid() -> Uid {
++    Uid(unsafe { libc::getuid() })
++}
++
++/// Get the effective user ID
++///
++/// See also [geteuid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/geteuid.html)
++// POSIX requires that geteuid is always successful, so no need to check return
++// value or errno.
++#[inline]
++pub fn geteuid() -> Uid {
++    Uid(unsafe { libc::geteuid() })
++}
++
++/// Get the real group ID
++///
++/// See also [getgid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getgid.html)
++// POSIX requires that getgid is always successful, so no need to check return
++// value or errno.
++#[inline]
++pub fn getgid() -> Gid {
++    Gid(unsafe { libc::getgid() })
++}
++
++/// Get the effective group ID
++///
++/// See also [getegid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getegid.html)
++// POSIX requires that getegid is always successful, so no need to check return
++// value or errno.
++#[inline]
++pub fn getegid() -> Gid {
++    Gid(unsafe { libc::getegid() })
++}
++
++/// Set the effective user ID
++///
++/// See also [seteuid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/seteuid.html)
++#[inline]
++pub fn seteuid(euid: Uid) -> Result<()> {
++    let res = unsafe { libc::seteuid(euid.into()) };
++
++    Errno::result(res).map(drop)
++}
++
++/// Set the effective group ID
++///
++/// See also [setegid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setegid.html)
++#[inline]
++pub fn setegid(egid: Gid) -> Result<()> {
++    let res = unsafe { libc::setegid(egid.into()) };
++
++    Errno::result(res).map(drop)
++}
++
++/// Set the user ID
++///
++/// See also [setuid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setuid.html)
++#[inline]
++pub fn setuid(uid: Uid) -> Result<()> {
++    let res = unsafe { libc::setuid(uid.into()) };
++
++    Errno::result(res).map(drop)
++}
++
++/// Set the group ID
++///
++/// See also [setgid(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/setgid.html)
++#[inline]
++pub fn setgid(gid: Gid) -> Result<()> {
++    let res = unsafe { libc::setgid(gid.into()) };
++
++    Errno::result(res).map(drop)
++}
++
++/// Get the list of supplementary group IDs of the calling process.
++///
++/// [Further reading](http://pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html)
++///
++/// **Note:** This function is not available for Apple platforms. On those
++/// platforms, checking group membership should be achieved via communication
++/// with the `opendirectoryd` service.
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++pub fn getgroups() -> Result<Vec<Gid>> {
++    // First get the number of groups so we can size our Vec
++    let ret = unsafe { libc::getgroups(0, ptr::null_mut()) };
++
++    // Now actually get the groups. We try multiple times in case the number of
++    // groups has changed since the first call to getgroups() and the buffer is
++    // now too small.
++    let mut groups = Vec::<Gid>::with_capacity(Errno::result(ret)? as usize);
++    loop {
++        // FIXME: On the platforms we currently support, the `Gid` struct has
++        // the same representation in memory as a bare `gid_t`. This is not
++        // necessarily the case on all Rust platforms, though. See RFC 1785.
++        let ret = unsafe {
++            libc::getgroups(groups.capacity() as c_int, groups.as_mut_ptr() as *mut gid_t)
++        };
++
++        match Errno::result(ret) {
++            Ok(s) => {
++                unsafe { groups.set_len(s as usize) };
++                return Ok(groups);
++            },
++            Err(Error::Sys(Errno::EINVAL)) => {
++                // EINVAL indicates that the buffer size was too small. Trigger
++                // the internal buffer resizing logic of `Vec` by requiring
++                // more space than the current capacity.
++                let cap = groups.capacity();
++                unsafe { groups.set_len(cap) };
++                groups.reserve(1);
++            },
++            Err(e) => return Err(e)
++        }
++    }
++}
++
++/// Set the list of supplementary group IDs for the calling process.
++///
++/// [Further reading](http://man7.org/linux/man-pages/man2/getgroups.2.html)
++///
++/// **Note:** This function is not available for Apple platforms. On those
++/// platforms, group membership management should be achieved via communication
++/// with the `opendirectoryd` service.
++///
++/// # Examples
++///
++/// `setgroups` can be used when dropping privileges from the root user to a
++/// specific user and group. For example, given the user `www-data` with UID
++/// `33` and the group `backup` with the GID `34`, one could switch the user as
++/// follows:
++///
++/// ```rust,no_run
++/// # use std::error::Error;
++/// # use nix::unistd::*;
++/// #
++/// # fn try_main() -> Result<(), Box<Error>> {
++/// let uid = Uid::from_raw(33);
++/// let gid = Gid::from_raw(34);
++/// setgroups(&[gid])?;
++/// setgid(gid)?;
++/// setuid(uid)?;
++/// #
++/// #     Ok(())
++/// # }
++/// #
++/// # fn main() {
++/// #     try_main().unwrap();
++/// # }
++/// ```
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++pub fn setgroups(groups: &[Gid]) -> Result<()> {
++    cfg_if! {
++        if #[cfg(any(target_os = "dragonfly",
++                     target_os = "freebsd",
++                     target_os = "ios",
++                     target_os = "macos",
++                     target_os = "netbsd",
++                     target_os = "openbsd"))] {
++            type setgroups_ngroups_t = c_int;
++        } else {
++            type setgroups_ngroups_t = size_t;
++        }
++    }
++    // FIXME: On the platforms we currently support, the `Gid` struct has the
++    // same representation in memory as a bare `gid_t`. This is not necessarily
++    // the case on all Rust platforms, though. See RFC 1785.
++    let res = unsafe {
++        libc::setgroups(groups.len() as setgroups_ngroups_t, groups.as_ptr() as *const gid_t)
++    };
++
++    Errno::result(res).map(drop)
++}
++
++/// Calculate the supplementary group access list.
++///
++/// Gets the group IDs of all groups that `user` is a member of. The additional
++/// group `group` is also added to the list.
++///
++/// [Further reading](http://man7.org/linux/man-pages/man3/getgrouplist.3.html)
++///
++/// **Note:** This function is not available for Apple platforms. On those
++/// platforms, checking group membership should be achieved via communication
++/// with the `opendirectoryd` service.
++///
++/// # Errors
++///
++/// Although the `getgrouplist()` call does not return any specific
++/// errors on any known platforms, this implementation will return a system
++/// error of `EINVAL` if the number of groups to be fetched exceeds the
++/// `NGROUPS_MAX` sysconf value. This mimics the behaviour of `getgroups()`
++/// and `setgroups()`. Additionally, while some implementations will return a
++/// partial list of groups when `NGROUPS_MAX` is exceeded, this implementation
++/// will only ever return the complete list or else an error.
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> {
++    let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) {
++        Ok(Some(n)) => n as c_int,
++        Ok(None) | Err(_) => <c_int>::max_value(),
++    };
++    use std::cmp::min;
++    let mut ngroups = min(ngroups_max, 8);
++    let mut groups = Vec::<Gid>::with_capacity(ngroups as usize);
++    cfg_if! {
++        if #[cfg(any(target_os = "ios", target_os = "macos"))] {
++            type getgrouplist_group_t = c_int;
++        } else {
++            type getgrouplist_group_t = gid_t;
++        }
++    }
++    let gid: gid_t = group.into();
++    loop {
++        let ret = unsafe {
++            libc::getgrouplist(user.as_ptr(),
++                               gid as getgrouplist_group_t,
++                               groups.as_mut_ptr() as *mut getgrouplist_group_t,
++                               &mut ngroups)
++        };
++
++        // BSD systems only return 0 or -1, Linux returns ngroups on success.
++        if ret >= 0 {
++            unsafe { groups.set_len(ngroups as usize) };
++            return Ok(groups);
++        } else if ret == -1 {
++            // Returns -1 if ngroups is too small, but does not set errno.
++            // BSD systems will still fill the groups buffer with as many
++            // groups as possible, but Linux manpages do not mention this
++            // behavior.
++
++            let cap = groups.capacity();
++            if cap >= ngroups_max as usize {
++                // We already have the largest capacity we can, give up
++                return Err(Error::invalid_argument());
++            }
++
++            // Reserve space for at least ngroups
++            groups.reserve(ngroups as usize);
++
++            // Even if the buffer gets resized to bigger than ngroups_max,
++            // don't ever ask for more than ngroups_max groups
++            ngroups = min(ngroups_max, groups.capacity() as c_int);
++        }
++    }
++}
++
++/// Initialize the supplementary group access list.
++///
++/// Sets the supplementary group IDs for the calling process using all groups
++/// that `user` is a member of. The additional group `group` is also added to
++/// the list.
++///
++/// [Further reading](http://man7.org/linux/man-pages/man3/initgroups.3.html)
++///
++/// **Note:** This function is not available for Apple platforms. On those
++/// platforms, group membership management should be achieved via communication
++/// with the `opendirectoryd` service.
++///
++/// # Examples
++///
++/// `initgroups` can be used when dropping privileges from the root user to
++/// another user. For example, given the user `www-data`, we could look up the
++/// UID and GID for the user in the system's password database (usually found
++/// in `/etc/passwd`). If the `www-data` user's UID and GID were `33` and `33`,
++/// respectively, one could switch the user as follows:
++///
++/// ```rust,no_run
++/// # use std::error::Error;
++/// # use std::ffi::CString;
++/// # use nix::unistd::*;
++/// #
++/// # fn try_main() -> Result<(), Box<Error>> {
++/// let user = CString::new("www-data").unwrap();
++/// let uid = Uid::from_raw(33);
++/// let gid = Gid::from_raw(33);
++/// initgroups(&user, gid)?;
++/// setgid(gid)?;
++/// setuid(uid)?;
++/// #
++/// #     Ok(())
++/// # }
++/// #
++/// # fn main() {
++/// #     try_main().unwrap();
++/// # }
++/// ```
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++pub fn initgroups(user: &CStr, group: Gid) -> Result<()> {
++    cfg_if! {
++        if #[cfg(any(target_os = "ios", target_os = "macos"))] {
++            type initgroups_group_t = c_int;
++        } else {
++            type initgroups_group_t = gid_t;
++        }
++    }
++    let gid: gid_t = group.into();
++    let res = unsafe { libc::initgroups(user.as_ptr(), gid as initgroups_group_t) };
++
++    Errno::result(res).map(drop)
++}
++
++/// Suspend the thread until a signal is received.
++///
++/// See also [pause(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pause.html).
++#[inline]
++pub fn pause() {
++    unsafe { libc::pause() };
++}
++
++pub mod alarm {
++    //! Alarm signal scheduling.
++    //!
++    //! Scheduling an alarm will trigger a `SIGALRM` signal when the time has
++    //! elapsed, which has to be caught, because the default action for the
++    //! signal is to terminate the program. This signal also can't be ignored
++    //! because the system calls like `pause` will not be interrupted, see the
++    //! second example below.
++    //!
++    //! # Examples
++    //!
++    //! Canceling an alarm:
++    //!
++    //! ```
++    //! use nix::unistd::alarm;
++    //!
++    //! // Set an alarm for 60 seconds from now.
++    //! alarm::set(60);
++    //!
++    //! // Cancel the above set alarm, which returns the number of seconds left
++    //! // of the previously set alarm.
++    //! assert_eq!(alarm::cancel(), Some(60));
++    //! ```
++    //!
++    //! Scheduling an alarm and waiting for the signal:
++    //!
++    //! ```
++    //! use std::time::{Duration, Instant};
++    //!
++    //! use nix::unistd::{alarm, pause};
++    //! use nix::sys::signal::*;
++    //!
++    //! // 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())); }
++    //!
++    //! // 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();
++    //!
++    //! assert!(start.elapsed() >= Duration::from_secs(1));
++    //! ```
++    //!
++    //! # References
++    //!
++    //! See also [alarm(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/alarm.html).
++
++    use libc;
++
++    /// Schedule an alarm signal.
++    ///
++    /// This will cause the system to generate a `SIGALRM` signal for the
++    /// process after the specified number of seconds have elapsed.
++    ///
++    /// Returns the leftover time of a previously set alarm if there was one.
++    pub fn set(secs: libc::c_uint) -> Option<libc::c_uint> {
++        assert!(secs != 0, "passing 0 to `alarm::set` is not allowed, to cancel an alarm use `alarm::cancel`");
++        alarm(secs)
++    }
++
++    /// Cancel an previously set alarm signal.
++    ///
++    /// Returns the leftover time of a previously set alarm if there was one.
++    pub fn cancel() -> Option<libc::c_uint> {
++        alarm(0)
++    }
++
++    fn alarm(secs: libc::c_uint) -> Option<libc::c_uint> {
++        match unsafe { libc::alarm(secs) } {
++            0 => None,
++            secs => Some(secs),
++        }
++    }
++}
++
++/// Suspend execution for an interval of time
++///
++/// See also [sleep(2)](http://pubs.opengroup.org/onlinepubs/009695399/functions/sleep.html#tag_03_705_05)
++// Per POSIX, does not fail
++#[inline]
++pub fn sleep(seconds: c_uint) -> c_uint {
++    unsafe { libc::sleep(seconds) }
++}
++
++pub mod acct {
++    use libc;
++    use {Result, NixPath};
++    use errno::Errno;
++    use std::ptr;
++
++    /// Enable process accounting
++    ///
++    /// See also [acct(2)](https://linux.die.net/man/2/acct)
++    pub fn enable<P: ?Sized + NixPath>(filename: &P) -> Result<()> {
++        let res = filename.with_nix_path(|cstr| {
++            unsafe { libc::acct(cstr.as_ptr()) }
++        })?;
++
++        Errno::result(res).map(drop)
++    }
++
++    /// Disable process accounting
++    pub fn disable() -> Result<()> {
++        let res = unsafe { libc::acct(ptr::null()) };
++
++        Errno::result(res).map(drop)
++    }
++}
++
++/// Creates a regular file which persists even after process termination
++///
++/// * `template`: a path whose 6 rightmost characters must be X, e.g. `/tmp/tmpfile_XXXXXX`
++/// * returns: tuple of file descriptor and filename
++///
++/// Err is returned either if no temporary filename could be created or the template doesn't
++/// end with XXXXXX
++///
++/// See also [mkstemp(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkstemp.html)
++///
++/// # Example
++///
++/// ```rust
++/// use nix::unistd;
++///
++/// let _ = match unistd::mkstemp("/tmp/tempfile_XXXXXX") {
++///     Ok((fd, path)) => {
++///         unistd::unlink(path.as_path()).unwrap(); // flag file to be deleted at app termination
++///         fd
++///     }
++///     Err(e) => panic!("mkstemp failed: {}", e)
++/// };
++/// // do something with fd
++/// ```
++#[inline]
++pub fn mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)> {
++    let mut path = template.with_nix_path(|path| {path.to_bytes_with_nul().to_owned()})?;
++    let p = path.as_mut_ptr() as *mut _;
++    let fd = unsafe { libc::mkstemp(p) };
++    let last = path.pop(); // drop the trailing nul
++    debug_assert!(last == Some(b'\0'));
++    let pathname = OsString::from_vec(path);
++    Errno::result(fd)?;
++    Ok((fd, PathBuf::from(pathname)))
++}
++
++/// Variable names for `pathconf`
++///
++/// Nix uses the same naming convention for these variables as the
++/// [getconf(1)](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html) utility.
++/// That is, `PathconfVar` variables have the same name as the abstract
++/// variables  shown in the `pathconf(2)` man page.  Usually, it's the same as
++/// the C variable name without the leading `_PC_`.
++///
++/// POSIX 1003.1-2008 standardizes all of these variables, but some OSes choose
++/// not to implement variables that cannot change at runtime.
++///
++/// # References
++///
++/// - [pathconf(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html)
++/// - [limits.h](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html)
++/// - [unistd.h](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html)
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++#[repr(i32)]
++pub enum PathconfVar {
++    #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux",
++              target_os = "netbsd", target_os = "openbsd"))]
++    /// Minimum number of bits needed to represent, as a signed integer value,
++    /// the maximum size of a regular file allowed in the specified directory.
++    FILESIZEBITS = libc::_PC_FILESIZEBITS,
++    /// Maximum number of links to a single file.
++    LINK_MAX = libc::_PC_LINK_MAX,
++    /// Maximum number of bytes in a terminal canonical input line.
++    MAX_CANON = libc::_PC_MAX_CANON,
++    /// Minimum number of bytes for which space is available in a terminal input
++    /// queue; therefore, the maximum number of bytes a conforming application
++    /// may require to be typed as input before reading them.
++    MAX_INPUT = libc::_PC_MAX_INPUT,
++    /// Maximum number of bytes in a filename (not including the terminating
++    /// null of a filename string).
++    NAME_MAX = libc::_PC_NAME_MAX,
++    /// Maximum number of bytes the implementation will store as a pathname in a
++    /// user-supplied buffer of unspecified size, including the terminating null
++    /// character. Minimum number the implementation will accept as the maximum
++    /// number of bytes in a pathname.
++    PATH_MAX = libc::_PC_PATH_MAX,
++    /// Maximum number of bytes that is guaranteed to be atomic when writing to
++    /// a pipe.
++    PIPE_BUF = libc::_PC_PIPE_BUF,
++    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "linux",
++              target_os = "netbsd", target_os = "openbsd"))]
++    /// Symbolic links can be created.
++    POSIX2_SYMLINKS = libc::_PC_2_SYMLINKS,
++    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
++              target_os = "linux", target_os = "openbsd"))]
++    /// Minimum number of bytes of storage actually allocated for any portion of
++    /// a file.
++    POSIX_ALLOC_SIZE_MIN = libc::_PC_ALLOC_SIZE_MIN,
++    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
++              target_os = "linux", target_os = "openbsd"))]
++    /// Recommended increment for file transfer sizes between the
++    /// `POSIX_REC_MIN_XFER_SIZE` and `POSIX_REC_MAX_XFER_SIZE` values.
++    POSIX_REC_INCR_XFER_SIZE = libc::_PC_REC_INCR_XFER_SIZE,
++    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
++              target_os = "linux", target_os = "openbsd"))]
++    /// Maximum recommended file transfer size.
++    POSIX_REC_MAX_XFER_SIZE = libc::_PC_REC_MAX_XFER_SIZE,
++    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
++              target_os = "linux", target_os = "openbsd"))]
++    /// Minimum recommended file transfer size.
++    POSIX_REC_MIN_XFER_SIZE = libc::_PC_REC_MIN_XFER_SIZE,
++    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
++              target_os = "linux", target_os = "openbsd"))]
++    ///  Recommended file transfer buffer alignment.
++    POSIX_REC_XFER_ALIGN = libc::_PC_REC_XFER_ALIGN,
++    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
++              target_os = "linux", target_os = "netbsd", target_os = "openbsd"))]
++    /// Maximum number of bytes in a symbolic link.
++    SYMLINK_MAX = libc::_PC_SYMLINK_MAX,
++    /// The use of `chown` and `fchown` is restricted to a process with
++    /// appropriate privileges, and to changing the group ID of a file only to
++    /// the effective group ID of the process or to one of its supplementary
++    /// group IDs.
++    _POSIX_CHOWN_RESTRICTED = libc::_PC_CHOWN_RESTRICTED,
++    /// Pathname components longer than {NAME_MAX} generate an error.
++    _POSIX_NO_TRUNC = libc::_PC_NO_TRUNC,
++    /// This symbol shall be defined to be the value of a character that shall
++    /// disable terminal special character handling.
++    _POSIX_VDISABLE = libc::_PC_VDISABLE,
++    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
++              target_os = "linux", target_os = "openbsd"))]
++    /// Asynchronous input or output operations may be performed for the
++    /// associated file.
++    _POSIX_ASYNC_IO = libc::_PC_ASYNC_IO,
++    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
++              target_os = "linux", target_os = "openbsd"))]
++    /// Prioritized input or output operations may be performed for the
++    /// associated file.
++    _POSIX_PRIO_IO = libc::_PC_PRIO_IO,
++    #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
++              target_os = "linux", target_os = "netbsd", target_os = "openbsd"))]
++    /// Synchronized input or output operations may be performed for the
++    /// associated file.
++    _POSIX_SYNC_IO = libc::_PC_SYNC_IO,
++    #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))]
++    /// The resolution in nanoseconds for all file timestamps.
++    _POSIX_TIMESTAMP_RESOLUTION = libc::_PC_TIMESTAMP_RESOLUTION
++}
++
++/// Like `pathconf`, but works with file descriptors instead of paths (see
++/// [fpathconf(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html))
++///
++/// # Parameters
++///
++/// - `fd`:   The file descriptor whose variable should be interrogated
++/// - `var`:  The pathconf variable to lookup
++///
++/// # Returns
++///
++/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its
++///     implementation level (for option variables).  Implementation levels are
++///     usually a decimal-coded date, such as 200112 for POSIX 2001.12
++/// - `Ok(None)`: the variable has no limit (for limit variables) or is
++///     unsupported (for option variables)
++/// - `Err(x)`: an error occurred
++pub fn fpathconf(fd: RawFd, var: PathconfVar) -> Result<Option<c_long>> {
++    let raw = unsafe {
++        Errno::clear();
++        libc::fpathconf(fd, var as c_int)
++    };
++    if raw == -1 {
++        if errno::errno() == 0 {
++            Ok(None)
++        } else {
++            Err(Error::Sys(Errno::last()))
++        }
++    } else {
++        Ok(Some(raw))
++    }
++}
++
++/// Get path-dependent configurable system variables (see
++/// [pathconf(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html))
++///
++/// Returns the value of a path-dependent configurable system variable.  Most
++/// supported variables also have associated compile-time constants, but POSIX
++/// allows their values to change at runtime.  There are generally two types of
++/// `pathconf` variables: options and limits.  See [pathconf(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html) for more details.
++///
++/// # Parameters
++///
++/// - `path`: Lookup the value of `var` for this file or directory
++/// - `var`:  The `pathconf` variable to lookup
++///
++/// # Returns
++///
++/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its
++///     implementation level (for option variables).  Implementation levels are
++///     usually a decimal-coded date, such as 200112 for POSIX 2001.12
++/// - `Ok(None)`: the variable has no limit (for limit variables) or is
++///     unsupported (for option variables)
++/// - `Err(x)`: an error occurred
++pub fn pathconf<P: ?Sized + NixPath>(path: &P, var: PathconfVar) -> Result<Option<c_long>> {
++    let raw = path.with_nix_path(|cstr| {
++        unsafe {
++            Errno::clear();
++            libc::pathconf(cstr.as_ptr(), var as c_int)
++        }
++    })?;
++    if raw == -1 {
++        if errno::errno() == 0 {
++            Ok(None)
++        } else {
++            Err(Error::Sys(Errno::last()))
++        }
++    } else {
++        Ok(Some(raw))
++    }
++}
++
++/// Variable names for `sysconf`
++///
++/// Nix uses the same naming convention for these variables as the
++/// [getconf(1)](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html) utility.
++/// That is, `SysconfVar` variables have the same name as the abstract variables
++/// shown in the `sysconf(3)` man page.  Usually, it's the same as the C
++/// variable name without the leading `_SC_`.
++///
++/// All of these symbols are standardized by POSIX 1003.1-2008, but haven't been
++/// implemented by all platforms.
++///
++/// # References
++///
++/// - [sysconf(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html)
++/// - [unistd.h](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html)
++/// - [limits.h](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html)
++#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++#[repr(i32)]
++pub enum SysconfVar {
++    /// Maximum number of I/O operations in a single list I/O call supported by
++    /// the implementation.
++    AIO_LISTIO_MAX = libc::_SC_AIO_LISTIO_MAX,
++    /// Maximum number of outstanding asynchronous I/O operations supported by
++    /// the implementation.
++    AIO_MAX = libc::_SC_AIO_MAX,
++    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
++              target_os = "ios", target_os="linux", target_os = "macos",
++              target_os="openbsd"))]
++    /// The maximum amount by which a process can decrease its asynchronous I/O
++    /// priority level from its own scheduling priority.
++    AIO_PRIO_DELTA_MAX = libc::_SC_AIO_PRIO_DELTA_MAX,
++    /// Maximum length of argument to the exec functions including environment data.
++    ARG_MAX = libc::_SC_ARG_MAX,
++    /// Maximum number of functions that may be registered with `atexit`.
++    ATEXIT_MAX = libc::_SC_ATEXIT_MAX,
++    /// Maximum obase values allowed by the bc utility.
++    BC_BASE_MAX = libc::_SC_BC_BASE_MAX,
++    /// Maximum number of elements permitted in an array by the bc utility.
++    BC_DIM_MAX = libc::_SC_BC_DIM_MAX,
++    /// Maximum scale value allowed by the bc utility.
++    BC_SCALE_MAX = libc::_SC_BC_SCALE_MAX,
++    /// Maximum length of a string constant accepted by the bc utility.
++    BC_STRING_MAX = libc::_SC_BC_STRING_MAX,
++    /// Maximum number of simultaneous processes per real user ID.
++    CHILD_MAX = libc::_SC_CHILD_MAX,
++    // _SC_CLK_TCK is obsolete
++    /// Maximum number of weights that can be assigned to an entry of the
++    /// LC_COLLATE order keyword in the locale definition file
++    COLL_WEIGHTS_MAX = libc::_SC_COLL_WEIGHTS_MAX,
++    /// Maximum number of timer expiration overruns.
++    DELAYTIMER_MAX = libc::_SC_DELAYTIMER_MAX,
++    /// Maximum number of expressions that can be nested within parentheses by
++    /// the expr utility.
++    EXPR_NEST_MAX = libc::_SC_EXPR_NEST_MAX,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="netbsd",
++              target_os="openbsd"))]
++    /// Maximum length of a host name (not including the terminating null) as
++    /// returned from the `gethostname` function
++    HOST_NAME_MAX = libc::_SC_HOST_NAME_MAX,
++    /// Maximum number of iovec structures that one process has available for
++    /// use with `readv` or `writev`.
++    IOV_MAX = libc::_SC_IOV_MAX,
++    /// Unless otherwise noted, the maximum length, in bytes, of a utility's
++    /// input line (either standard input or another file), when the utility is
++    /// described as processing text files. The length includes room for the
++    /// trailing <newline>.
++    LINE_MAX = libc::_SC_LINE_MAX,
++    /// Maximum length of a login name.
++    LOGIN_NAME_MAX = libc::_SC_LOGIN_NAME_MAX,
++    /// Maximum number of simultaneous supplementary group IDs per process.
++    NGROUPS_MAX = libc::_SC_NGROUPS_MAX,
++    /// Initial size of `getgrgid_r` and `getgrnam_r` data buffers
++    GETGR_R_SIZE_MAX = libc::_SC_GETGR_R_SIZE_MAX,
++    /// Initial size of `getpwuid_r` and `getpwnam_r` data buffers
++    GETPW_R_SIZE_MAX = libc::_SC_GETPW_R_SIZE_MAX,
++    /// The maximum number of open message queue descriptors a process may hold.
++    MQ_OPEN_MAX = libc::_SC_MQ_OPEN_MAX,
++    /// The maximum number of message priorities supported by the implementation.
++    MQ_PRIO_MAX = libc::_SC_MQ_PRIO_MAX,
++    /// A value one greater than the maximum value that the system may assign to
++    /// a newly-created file descriptor.
++    OPEN_MAX = libc::_SC_OPEN_MAX,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="openbsd"))]
++    /// The implementation supports the Advisory Information option.
++    _POSIX_ADVISORY_INFO = libc::_SC_ADVISORY_INFO,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="netbsd",
++              target_os="openbsd"))]
++    /// The implementation supports barriers.
++    _POSIX_BARRIERS = libc::_SC_BARRIERS,
++    /// The implementation supports asynchronous input and output.
++    _POSIX_ASYNCHRONOUS_IO = libc::_SC_ASYNCHRONOUS_IO,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="netbsd",
++              target_os="openbsd"))]
++    /// The implementation supports clock selection.
++    _POSIX_CLOCK_SELECTION = libc::_SC_CLOCK_SELECTION,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="netbsd",
++              target_os="openbsd"))]
++    /// The implementation supports the Process CPU-Time Clocks option.
++    _POSIX_CPUTIME = libc::_SC_CPUTIME,
++    /// The implementation supports the File Synchronization option.
++    _POSIX_FSYNC = libc::_SC_FSYNC,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="openbsd"))]
++    /// The implementation supports the IPv6 option.
++    _POSIX_IPV6 = libc::_SC_IPV6,
++    /// The implementation supports job control.
++    _POSIX_JOB_CONTROL = libc::_SC_JOB_CONTROL,
++    /// The implementation supports memory mapped Files.
++    _POSIX_MAPPED_FILES = libc::_SC_MAPPED_FILES,
++    /// The implementation supports the Process Memory Locking option.
++    _POSIX_MEMLOCK = libc::_SC_MEMLOCK,
++    /// The implementation supports the Range Memory Locking option.
++    _POSIX_MEMLOCK_RANGE = libc::_SC_MEMLOCK_RANGE,
++    /// The implementation supports memory protection.
++    _POSIX_MEMORY_PROTECTION = libc::_SC_MEMORY_PROTECTION,
++    /// The implementation supports the Message Passing option.
++    _POSIX_MESSAGE_PASSING = libc::_SC_MESSAGE_PASSING,
++    /// The implementation supports the Monotonic Clock option.
++    _POSIX_MONOTONIC_CLOCK = libc::_SC_MONOTONIC_CLOCK,
++    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
++              target_os = "ios", target_os="linux", target_os = "macos",
++              target_os="openbsd"))]
++    /// The implementation supports the Prioritized Input and Output option.
++    _POSIX_PRIORITIZED_IO = libc::_SC_PRIORITIZED_IO,
++    /// The implementation supports the Process Scheduling option.
++    _POSIX_PRIORITY_SCHEDULING = libc::_SC_PRIORITY_SCHEDULING,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="openbsd"))]
++    /// The implementation supports the Raw Sockets option.
++    _POSIX_RAW_SOCKETS = libc::_SC_RAW_SOCKETS,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="netbsd",
++              target_os="openbsd"))]
++    /// The implementation supports read-write locks.
++    _POSIX_READER_WRITER_LOCKS = libc::_SC_READER_WRITER_LOCKS,
++    #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd",
++              target_os = "ios", target_os="linux", target_os = "macos",
++              target_os = "openbsd"))]
++    /// The implementation supports realtime signals.
++    _POSIX_REALTIME_SIGNALS = libc::_SC_REALTIME_SIGNALS,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="netbsd",
++              target_os="openbsd"))]
++    /// The implementation supports the Regular Expression Handling option.
++    _POSIX_REGEXP = libc::_SC_REGEXP,
++    /// Each process has a saved set-user-ID and a saved set-group-ID.
++    _POSIX_SAVED_IDS = libc::_SC_SAVED_IDS,
++    /// The implementation supports semaphores.
++    _POSIX_SEMAPHORES = libc::_SC_SEMAPHORES,
++    /// The implementation supports the Shared Memory Objects option.
++    _POSIX_SHARED_MEMORY_OBJECTS = libc::_SC_SHARED_MEMORY_OBJECTS,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="netbsd",
++              target_os="openbsd"))]
++    /// The implementation supports the POSIX shell.
++    _POSIX_SHELL = libc::_SC_SHELL,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="netbsd",
++              target_os="openbsd"))]
++    /// The implementation supports the Spawn option.
++    _POSIX_SPAWN = libc::_SC_SPAWN,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="netbsd",
++              target_os="openbsd"))]
++    /// The implementation supports spin locks.
++    _POSIX_SPIN_LOCKS = libc::_SC_SPIN_LOCKS,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="openbsd"))]
++    /// The implementation supports the Process Sporadic Server option.
++    _POSIX_SPORADIC_SERVER = libc::_SC_SPORADIC_SERVER,
++    #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
++              target_os="openbsd"))]
++    _POSIX_SS_REPL_MAX = libc::_SC_SS_REPL_MAX,
++    /// The implementation supports the Synchronized Input and Output option.
++    _POSIX_SYNCHRONIZED_IO = libc::_SC_SYNCHRONIZED_IO,
++    /// The implementation supports the Thread Stack Address Attribute option.
++    _POSIX_THREAD_ATTR_STACKADDR = libc::_SC_THREAD_ATTR_STACKADDR,
++    /// The implementation supports the Thread Stack Size Attribute option.
++    _POSIX_THREAD_ATTR_STACKSIZE = libc::_SC_THREAD_ATTR_STACKSIZE,
++    #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
++              target_os="netbsd", target_os="openbsd"))]
++    /// The implementation supports the Thread CPU-Time Clocks option.
++    _POSIX_THREAD_CPUTIME = libc::_SC_THREAD_CPUTIME,
++    /// The implementation supports the Non-Robust Mutex Priority Inheritance
++    /// option.
++    _POSIX_THREAD_PRIO_INHERIT = libc::_SC_THREAD_PRIO_INHERIT,
++    /// The implementation supports the Non-Robust Mutex Priority Protection option.
++    _POSIX_THREAD_PRIO_PROTECT = libc::_SC_THREAD_PRIO_PROTECT,
++    /// The implementation supports the Thread Execution Scheduling option.
++    _POSIX_THREAD_PRIORITY_SCHEDULING = libc::_SC_THREAD_PRIORITY_SCHEDULING,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="netbsd",
++              target_os="openbsd"))]
++    /// The implementation supports the Thread Process-Shared Synchronization
++    /// option.
++    _POSIX_THREAD_PROCESS_SHARED = libc::_SC_THREAD_PROCESS_SHARED,
++    #[cfg(any(target_os="dragonfly", target_os="linux", target_os="openbsd"))]
++    /// The implementation supports the Robust Mutex Priority Inheritance option.
++    _POSIX_THREAD_ROBUST_PRIO_INHERIT = libc::_SC_THREAD_ROBUST_PRIO_INHERIT,
++    #[cfg(any(target_os="dragonfly", target_os="linux", target_os="openbsd"))]
++    /// The implementation supports the Robust Mutex Priority Protection option.
++    _POSIX_THREAD_ROBUST_PRIO_PROTECT = libc::_SC_THREAD_ROBUST_PRIO_PROTECT,
++    /// The implementation supports thread-safe functions.
++    _POSIX_THREAD_SAFE_FUNCTIONS = libc::_SC_THREAD_SAFE_FUNCTIONS,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="openbsd"))]
++    /// The implementation supports the Thread Sporadic Server option.
++    _POSIX_THREAD_SPORADIC_SERVER = libc::_SC_THREAD_SPORADIC_SERVER,
++    /// The implementation supports threads.
++    _POSIX_THREADS = libc::_SC_THREADS,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="openbsd"))]
++    /// The implementation supports timeouts.
++    _POSIX_TIMEOUTS = libc::_SC_TIMEOUTS,
++    /// The implementation supports timers.
++    _POSIX_TIMERS = libc::_SC_TIMERS,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="openbsd"))]
++    /// The implementation supports the Trace option.
++    _POSIX_TRACE = libc::_SC_TRACE,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="openbsd"))]
++    /// The implementation supports the Trace Event Filter option.
++    _POSIX_TRACE_EVENT_FILTER = libc::_SC_TRACE_EVENT_FILTER,
++    #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
++              target_os="openbsd"))]
++    _POSIX_TRACE_EVENT_NAME_MAX = libc::_SC_TRACE_EVENT_NAME_MAX,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="openbsd"))]
++    /// The implementation supports the Trace Inherit option.
++    _POSIX_TRACE_INHERIT = libc::_SC_TRACE_INHERIT,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="openbsd"))]
++    /// The implementation supports the Trace Log option.
++    _POSIX_TRACE_LOG = libc::_SC_TRACE_LOG,
++    #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
++              target_os="openbsd"))]
++    _POSIX_TRACE_NAME_MAX = libc::_SC_TRACE_NAME_MAX,
++    #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
++              target_os="openbsd"))]
++    _POSIX_TRACE_SYS_MAX = libc::_SC_TRACE_SYS_MAX,
++    #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
++              target_os="openbsd"))]
++    _POSIX_TRACE_USER_EVENT_MAX = libc::_SC_TRACE_USER_EVENT_MAX,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="openbsd"))]
++    /// The implementation supports the Typed Memory Objects option.
++    _POSIX_TYPED_MEMORY_OBJECTS = libc::_SC_TYPED_MEMORY_OBJECTS,
++    /// Integer value indicating version of this standard (C-language binding)
++    /// to which the implementation conforms. For implementations conforming to
++    /// POSIX.1-2008, the value shall be 200809L.
++    _POSIX_VERSION = libc::_SC_VERSION,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="netbsd",
++              target_os="openbsd"))]
++    /// The implementation provides a C-language compilation environment with
++    /// 32-bit `int`, `long`, `pointer`, and `off_t` types.
++    _POSIX_V6_ILP32_OFF32 = libc::_SC_V6_ILP32_OFF32,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="netbsd",
++              target_os="openbsd"))]
++    /// The implementation provides a C-language compilation environment with
++    /// 32-bit `int`, `long`, and pointer types and an `off_t` type using at
++    /// least 64 bits.
++    _POSIX_V6_ILP32_OFFBIG = libc::_SC_V6_ILP32_OFFBIG,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="netbsd",
++              target_os="openbsd"))]
++    /// The implementation provides a C-language compilation environment with
++    /// 32-bit `int` and 64-bit `long`, `pointer`, and `off_t` types.
++    _POSIX_V6_LP64_OFF64 = libc::_SC_V6_LP64_OFF64,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="netbsd",
++              target_os="openbsd"))]
++    /// The implementation provides a C-language compilation environment with an
++    /// `int` type using at least 32 bits and `long`, pointer, and `off_t` types
++    /// using at least 64 bits.
++    _POSIX_V6_LPBIG_OFFBIG = libc::_SC_V6_LPBIG_OFFBIG,
++    /// The implementation supports the C-Language Binding option.
++    _POSIX2_C_BIND = libc::_SC_2_C_BIND,
++    /// The implementation supports the C-Language Development Utilities option.
++    _POSIX2_C_DEV = libc::_SC_2_C_DEV,
++    /// The implementation supports the Terminal Characteristics option.
++    _POSIX2_CHAR_TERM = libc::_SC_2_CHAR_TERM,
++    /// The implementation supports the FORTRAN Development Utilities option.
++    _POSIX2_FORT_DEV = libc::_SC_2_FORT_DEV,
++    /// The implementation supports the FORTRAN Runtime Utilities option.
++    _POSIX2_FORT_RUN = libc::_SC_2_FORT_RUN,
++    /// The implementation supports the creation of locales by the localedef
++    /// utility.
++    _POSIX2_LOCALEDEF = libc::_SC_2_LOCALEDEF,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="netbsd",
++              target_os="openbsd"))]
++    /// The implementation supports the Batch Environment Services and Utilities
++    /// option.
++    _POSIX2_PBS = libc::_SC_2_PBS,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="netbsd",
++              target_os="openbsd"))]
++    /// The implementation supports the Batch Accounting option.
++    _POSIX2_PBS_ACCOUNTING = libc::_SC_2_PBS_ACCOUNTING,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="netbsd",
++              target_os="openbsd"))]
++    /// The implementation supports the Batch Checkpoint/Restart option.
++    _POSIX2_PBS_CHECKPOINT = libc::_SC_2_PBS_CHECKPOINT,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="netbsd",
++              target_os="openbsd"))]
++    /// The implementation supports the Locate Batch Job Request option.
++    _POSIX2_PBS_LOCATE = libc::_SC_2_PBS_LOCATE,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="netbsd",
++              target_os="openbsd"))]
++    /// The implementation supports the Batch Job Message Request option.
++    _POSIX2_PBS_MESSAGE = libc::_SC_2_PBS_MESSAGE,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="netbsd",
++              target_os="openbsd"))]
++    /// The implementation supports the Track Batch Job Request option.
++    _POSIX2_PBS_TRACK = libc::_SC_2_PBS_TRACK,
++    /// The implementation supports the Software Development Utilities option.
++    _POSIX2_SW_DEV = libc::_SC_2_SW_DEV,
++    /// The implementation supports the User Portability Utilities option.
++    _POSIX2_UPE = libc::_SC_2_UPE,
++    /// Integer value indicating version of the Shell and Utilities volume of
++    /// POSIX.1 to which the implementation conforms.
++    _POSIX2_VERSION = libc::_SC_2_VERSION,
++    /// The size of a system page in bytes.
++    ///
++    /// POSIX also defines an alias named `PAGESIZE`, but Rust does not allow two
++    /// enum constants to have the same value, so nix omits `PAGESIZE`.
++    PAGE_SIZE = libc::_SC_PAGE_SIZE,
++    PTHREAD_DESTRUCTOR_ITERATIONS = libc::_SC_THREAD_DESTRUCTOR_ITERATIONS,
++    PTHREAD_KEYS_MAX = libc::_SC_THREAD_KEYS_MAX,
++    PTHREAD_STACK_MIN = libc::_SC_THREAD_STACK_MIN,
++    PTHREAD_THREADS_MAX = libc::_SC_THREAD_THREADS_MAX,
++    RE_DUP_MAX = libc::_SC_RE_DUP_MAX,
++    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
++              target_os = "ios", target_os="linux", target_os = "macos",
++              target_os="openbsd"))]
++    RTSIG_MAX = libc::_SC_RTSIG_MAX,
++    SEM_NSEMS_MAX = libc::_SC_SEM_NSEMS_MAX,
++    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
++              target_os = "ios", target_os="linux", target_os = "macos",
++              target_os="openbsd"))]
++    SEM_VALUE_MAX = libc::_SC_SEM_VALUE_MAX,
++    #[cfg(any(target_os = "android", target_os="dragonfly", target_os="freebsd",
++              target_os = "ios", target_os="linux", target_os = "macos",
++              target_os = "openbsd"))]
++    SIGQUEUE_MAX = libc::_SC_SIGQUEUE_MAX,
++    STREAM_MAX = libc::_SC_STREAM_MAX,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="netbsd",
++              target_os="openbsd"))]
++    SYMLOOP_MAX = libc::_SC_SYMLOOP_MAX,
++    TIMER_MAX = libc::_SC_TIMER_MAX,
++    TTY_NAME_MAX = libc::_SC_TTY_NAME_MAX,
++    TZNAME_MAX = libc::_SC_TZNAME_MAX,
++    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
++              target_os = "ios", target_os="linux", target_os = "macos",
++              target_os="openbsd"))]
++    /// The implementation supports the X/Open Encryption Option Group.
++    _XOPEN_CRYPT = libc::_SC_XOPEN_CRYPT,
++    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
++              target_os = "ios", target_os="linux", target_os = "macos",
++              target_os="openbsd"))]
++    /// The implementation supports the Issue 4, Version 2 Enhanced
++    /// Internationalization Option Group.
++    _XOPEN_ENH_I18N = libc::_SC_XOPEN_ENH_I18N,
++    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
++              target_os = "ios", target_os="linux", target_os = "macos",
++              target_os="openbsd"))]
++    _XOPEN_LEGACY = libc::_SC_XOPEN_LEGACY,
++    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
++              target_os = "ios", target_os="linux", target_os = "macos",
++              target_os="openbsd"))]
++    /// The implementation supports the X/Open Realtime Option Group.
++    _XOPEN_REALTIME = libc::_SC_XOPEN_REALTIME,
++    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
++              target_os = "ios", target_os="linux", target_os = "macos",
++              target_os="openbsd"))]
++    /// The implementation supports the X/Open Realtime Threads Option Group.
++    _XOPEN_REALTIME_THREADS = libc::_SC_XOPEN_REALTIME_THREADS,
++    /// The implementation supports the Issue 4, Version 2 Shared Memory Option
++    /// Group.
++    _XOPEN_SHM = libc::_SC_XOPEN_SHM,
++    #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
++              target_os="linux", target_os = "macos", target_os="openbsd"))]
++    /// The implementation supports the XSI STREAMS Option Group.
++    _XOPEN_STREAMS = libc::_SC_XOPEN_STREAMS,
++    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
++              target_os = "ios", target_os="linux", target_os = "macos",
++              target_os="openbsd"))]
++    /// The implementation supports the XSI option
++    _XOPEN_UNIX = libc::_SC_XOPEN_UNIX,
++    #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
++              target_os = "ios", target_os="linux", target_os = "macos",
++              target_os="openbsd"))]
++    /// Integer value indicating version of the X/Open Portability Guide to
++    /// which the implementation conforms.
++    _XOPEN_VERSION = libc::_SC_XOPEN_VERSION,
++}
++
++/// Get configurable system variables (see
++/// [sysconf(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html))
++///
++/// Returns the value of a configurable system variable.  Most supported
++/// variables also have associated compile-time constants, but POSIX
++/// allows their values to change at runtime.  There are generally two types of
++/// sysconf variables: options and limits.  See sysconf(3) for more details.
++///
++/// # Returns
++///
++/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its
++///     implementation level (for option variables).  Implementation levels are
++///     usually a decimal-coded date, such as 200112 for POSIX 2001.12
++/// - `Ok(None)`: the variable has no limit (for limit variables) or is
++///     unsupported (for option variables)
++/// - `Err(x)`: an error occurred
++pub fn sysconf(var: SysconfVar) -> Result<Option<c_long>> {
++    let raw = unsafe {
++        Errno::clear();
++        libc::sysconf(var as c_int)
++    };
++    if raw == -1 {
++        if errno::errno() == 0 {
++            Ok(None)
++        } else {
++            Err(Error::Sys(Errno::last()))
++        }
++    } else {
++        Ok(Some(raw))
++    }
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++mod pivot_root {
++    use libc;
++    use {Result, NixPath};
++    use errno::Errno;
++
++    pub fn pivot_root<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
++            new_root: &P1, put_old: &P2) -> Result<()> {
++        let res = new_root.with_nix_path(|new_root| {
++            put_old.with_nix_path(|put_old| {
++                unsafe {
++                    libc::syscall(libc::SYS_pivot_root, new_root.as_ptr(), put_old.as_ptr())
++                }
++            })
++        })??;
++
++        Errno::result(res).map(drop)
++    }
++}
++
++#[cfg(any(target_os = "android", target_os = "freebsd",
++          target_os = "linux", target_os = "openbsd"))]
++mod setres {
++    use libc;
++    use Result;
++    use errno::Errno;
++    use super::{Uid, Gid};
++
++    /// Sets the real, effective, and saved uid.
++    /// ([see setresuid(2)](http://man7.org/linux/man-pages/man2/setresuid.2.html))
++    ///
++    /// * `ruid`: real user id
++    /// * `euid`: effective user id
++    /// * `suid`: saved user id
++    /// * returns: Ok or libc error code.
++    ///
++    /// Err is returned if the user doesn't have permission to set this UID.
++    #[inline]
++    pub fn setresuid(ruid: Uid, euid: Uid, suid: Uid) -> Result<()> {
++        let res = unsafe { libc::setresuid(ruid.into(), euid.into(), suid.into()) };
++
++        Errno::result(res).map(drop)
++    }
++
++    /// Sets the real, effective, and saved gid.
++    /// ([see setresuid(2)](http://man7.org/linux/man-pages/man2/setresuid.2.html))
++    ///
++    /// * `rgid`: real group id
++    /// * `egid`: effective group id
++    /// * `sgid`: saved group id
++    /// * returns: Ok or libc error code.
++    ///
++    /// Err is returned if the user doesn't have permission to set this GID.
++    #[inline]
++    pub fn setresgid(rgid: Gid, egid: Gid, sgid: Gid) -> Result<()> {
++        let res = unsafe { libc::setresgid(rgid.into(), egid.into(), sgid.into()) };
++
++        Errno::result(res).map(drop)
++    }
++}
++
++libc_bitflags!{
++    /// Options for access()
++    pub struct AccessFlags : c_int {
++        /// Test for existence of file.
++        F_OK;
++        /// Test for read permission.
++        R_OK;
++        /// Test for write permission.
++        W_OK;
++        /// Test for execute (search) permission.
++        X_OK;
++    }
++}
++
++/// Checks the file named by `path` for accessibility according to the flags given by `amode`
++/// See [access(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html)
++pub fn access<P: ?Sized + NixPath>(path: &P, amode: AccessFlags) -> Result<()> {
++    let res = path.with_nix_path(|cstr| {
++        unsafe {
++            libc::access(cstr.as_ptr(), amode.bits)
++        }
++    })?;
++    Errno::result(res).map(drop)
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/mod.rs b/third_party/rust/nix-0.15.0/test/sys/mod.rs
+new file mode 100644
+index 0000000000000..60a58dd106f19
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/mod.rs
+@@ -0,0 +1,38 @@
++mod test_signal;
++
++// NOTE: DragonFly lacks a kernel-level implementation of Posix AIO as of
++// this writing. There is an user-level implementation, but whether aio
++// works or not heavily depends on which pthread implementation is chosen
++// by the user at link time. For this reason we do not want to run aio test
++// cases on DragonFly.
++#[cfg(any(target_os = "freebsd",
++          target_os = "ios",
++          target_os = "linux",
++          target_os = "macos",
++          target_os = "netbsd"))]
++mod test_aio;
++#[cfg(target_os = "linux")]
++mod test_signalfd;
++mod test_socket;
++mod test_sockopt;
++mod test_select;
++#[cfg(any(target_os = "android", target_os = "linux"))]
++mod test_sysinfo;
++mod test_termios;
++mod test_ioctl;
++mod test_wait;
++mod test_uio;
++
++#[cfg(target_os = "linux")]
++mod test_epoll;
++#[cfg(target_os = "linux")]
++mod test_inotify;
++mod test_pthread;
++#[cfg(any(target_os = "android",
++          target_os = "dragonfly",
++          target_os = "freebsd",
++          target_os = "linux",
++          target_os = "macos",
++          target_os = "netbsd",
++          target_os = "openbsd"))]
++mod test_ptrace;
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_aio.rs b/third_party/rust/nix-0.15.0/test/sys/test_aio.rs
+new file mode 100644
+index 0000000000000..d4b09b0b81905
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_aio.rs
+@@ -0,0 +1,654 @@
++use bytes::{Bytes, BytesMut};
++use libc::{c_int, c_void};
++use nix::{Error, Result};
++use nix::errno::*;
++use nix::sys::aio::*;
++use nix::sys::signal::{SaFlags, SigAction, sigaction, SigevNotify, SigHandler, Signal, SigSet};
++use nix::sys::time::{TimeSpec, TimeValLike};
++use std::io::{Write, Read, Seek, SeekFrom};
++use std::ops::Deref;
++use std::os::unix::io::AsRawFd;
++use std::sync::atomic::{AtomicBool, Ordering};
++use std::{thread, time};
++use tempfile::tempfile;
++
++// Helper that polls an AioCb for completion or error
++fn poll_aio(aiocb: &mut AioCb) -> Result<()> {
++    loop {
++        let err = aiocb.error();
++        if err != Err(Error::from(Errno::EINPROGRESS)) { return err; };
++        thread::sleep(time::Duration::from_millis(10));
++    }
++}
++
++#[test]
++fn test_accessors() {
++    let mut rbuf = vec![0; 4];
++    let aiocb = AioCb::from_mut_slice( 1001,
++                           2,   //offset
++                           &mut rbuf,
++                           42,   //priority
++                           SigevNotify::SigevSignal {
++                               signal: Signal::SIGUSR2,
++                               si_value: 99
++                           },
++                           LioOpcode::LIO_NOP);
++    assert_eq!(1001, aiocb.fd());
++    assert_eq!(Some(LioOpcode::LIO_NOP), aiocb.lio_opcode());
++    assert_eq!(4, aiocb.nbytes());
++    assert_eq!(2, aiocb.offset());
++    assert_eq!(42, aiocb.priority());
++    let sev = aiocb.sigevent().sigevent();
++    assert_eq!(Signal::SIGUSR2 as i32, sev.sigev_signo);
++    assert_eq!(99, sev.sigev_value.sival_ptr as i64);
++}
++
++// Tests AioCb.cancel.  We aren't trying to test the OS's implementation, only
++// our bindings.  So it's sufficient to check that AioCb.cancel returned any
++// AioCancelStat value.
++#[test]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_cancel() {
++    let wbuf: &[u8] = b"CDEF";
++
++    let f = tempfile().unwrap();
++    let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
++                            0,   //offset
++                            wbuf,
++                            0,   //priority
++                            SigevNotify::SigevNone,
++                            LioOpcode::LIO_NOP);
++    aiocb.write().unwrap();
++    let err = aiocb.error();
++    assert!(err == Ok(()) || err == Err(Error::from(Errno::EINPROGRESS)));
++
++    let cancelstat = aiocb.cancel();
++    assert!(cancelstat.is_ok());
++
++    // Wait for aiocb to complete, but don't care whether it succeeded
++    let _ = poll_aio(&mut aiocb);
++    let _ = aiocb.aio_return();
++}
++
++// Tests using aio_cancel_all for all outstanding IOs.
++#[test]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_aio_cancel_all() {
++    let wbuf: &[u8] = b"CDEF";
++
++    let f = tempfile().unwrap();
++    let mut aiocb = AioCb::from_slice(f.as_raw_fd(),
++                            0,   //offset
++                            wbuf,
++                            0,   //priority
++                            SigevNotify::SigevNone,
++                            LioOpcode::LIO_NOP);
++    aiocb.write().unwrap();
++    let err = aiocb.error();
++    assert!(err == Ok(()) || err == Err(Error::from(Errno::EINPROGRESS)));
++
++    let cancelstat = aio_cancel_all(f.as_raw_fd());
++    assert!(cancelstat.is_ok());
++
++    // Wait for aiocb to complete, but don't care whether it succeeded
++    let _ = poll_aio(&mut aiocb);
++    let _ = aiocb.aio_return();
++}
++
++#[test]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_fsync() {
++    const INITIAL: &[u8] = b"abcdef123456";
++    let mut f = tempfile().unwrap();
++    f.write_all(INITIAL).unwrap();
++    let mut aiocb = AioCb::from_fd( f.as_raw_fd(),
++                            0,   //priority
++                            SigevNotify::SigevNone);
++    let err = aiocb.fsync(AioFsyncMode::O_SYNC);
++    assert!(err.is_ok());
++    poll_aio(&mut aiocb).unwrap();
++    aiocb.aio_return().unwrap();
++}
++
++/// `AioCb::fsync` should not modify the `AioCb` object if `libc::aio_fsync` returns
++/// an error
++// Skip on Linux, because Linux's AIO implementation can't detect errors
++// synchronously
++#[test]
++#[cfg(any(target_os = "freebsd", target_os = "macos"))]
++fn test_fsync_error() {
++    use std::mem;
++
++    const INITIAL: &[u8] = b"abcdef123456";
++    // Create an invalid AioFsyncMode
++    let mode = unsafe { mem::transmute(666) };
++    let mut f = tempfile().unwrap();
++    f.write_all(INITIAL).unwrap();
++    let mut aiocb = AioCb::from_fd( f.as_raw_fd(),
++                            0,   //priority
++                            SigevNotify::SigevNone);
++    let err = aiocb.fsync(mode);
++    assert!(err.is_err());
++}
++
++#[test]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_aio_suspend() {
++    const INITIAL: &[u8] = b"abcdef123456";
++    const WBUF: &[u8] = b"CDEFG";
++    let timeout = TimeSpec::seconds(10);
++    let mut rbuf = vec![0; 4];
++    let rlen = rbuf.len();
++    let mut f = tempfile().unwrap();
++    f.write_all(INITIAL).unwrap();
++
++    let mut wcb = AioCb::from_slice( f.as_raw_fd(),
++                           2,   //offset
++                           WBUF,
++                           0,   //priority
++                           SigevNotify::SigevNone,
++                           LioOpcode::LIO_WRITE);
++
++    let mut rcb = AioCb::from_mut_slice( f.as_raw_fd(),
++                            8,   //offset
++                            &mut rbuf,
++                            0,   //priority
++                            SigevNotify::SigevNone,
++                            LioOpcode::LIO_READ);
++    wcb.write().unwrap();
++    rcb.read().unwrap();
++    loop {
++        {
++            let cbbuf = [&wcb, &rcb];
++            assert!(aio_suspend(&cbbuf[..], Some(timeout)).is_ok());
++        }
++        if rcb.error() != Err(Error::from(Errno::EINPROGRESS)) &&
++           wcb.error() != Err(Error::from(Errno::EINPROGRESS)) {
++            break
++        }
++    }
++
++    assert!(wcb.aio_return().unwrap() as usize == WBUF.len());
++    assert!(rcb.aio_return().unwrap() as usize == rlen);
++}
++
++// Test a simple aio operation with no completion notification.  We must poll
++// for completion
++#[test]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_read() {
++    const INITIAL: &[u8] = b"abcdef123456";
++    let mut rbuf = vec![0; 4];
++    const EXPECT: &[u8] = b"cdef";
++    let mut f = tempfile().unwrap();
++    f.write_all(INITIAL).unwrap();
++    {
++        let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(),
++                               2,   //offset
++                               &mut rbuf,
++                               0,   //priority
++                               SigevNotify::SigevNone,
++                               LioOpcode::LIO_NOP);
++        aiocb.read().unwrap();
++
++        let err = poll_aio(&mut aiocb);
++        assert!(err == Ok(()));
++        assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len());
++    }
++
++    assert!(EXPECT == rbuf.deref().deref());
++}
++
++/// `AioCb::read` should not modify the `AioCb` object if `libc::aio_read`
++/// returns an error
++// Skip on Linux, because Linux's AIO implementation can't detect errors
++// synchronously
++#[test]
++#[cfg(any(target_os = "freebsd", target_os = "macos"))]
++fn test_read_error() {
++    const INITIAL: &[u8] = b"abcdef123456";
++    let mut rbuf = vec![0; 4];
++    let mut f = tempfile().unwrap();
++    f.write_all(INITIAL).unwrap();
++    let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(),
++                           -1,   //an invalid offset
++                           &mut rbuf,
++                           0,   //priority
++                           SigevNotify::SigevNone,
++                           LioOpcode::LIO_NOP);
++    assert!(aiocb.read().is_err());
++}
++
++// Tests from_mut_slice
++#[test]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_read_into_mut_slice() {
++    const INITIAL: &[u8] = b"abcdef123456";
++    let mut rbuf = vec![0; 4];
++    const EXPECT: &[u8] = b"cdef";
++    let mut f = tempfile().unwrap();
++    f.write_all(INITIAL).unwrap();
++    {
++        let mut aiocb = AioCb::from_mut_slice( f.as_raw_fd(),
++                               2,   //offset
++                               &mut rbuf,
++                               0,   //priority
++                               SigevNotify::SigevNone,
++                               LioOpcode::LIO_NOP);
++        aiocb.read().unwrap();
++
++        let err = poll_aio(&mut aiocb);
++        assert!(err == Ok(()));
++        assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len());
++    }
++
++    assert!(rbuf == EXPECT);
++}
++
++// Tests from_ptr
++#[test]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_read_into_pointer() {
++    const INITIAL: &[u8] = b"abcdef123456";
++    let mut rbuf = vec![0; 4];
++    const EXPECT: &[u8] = b"cdef";
++    let mut f = tempfile().unwrap();
++    f.write_all(INITIAL).unwrap();
++    {
++        // Safety: ok because rbuf lives until after poll_aio
++        let mut aiocb = unsafe {
++            AioCb::from_mut_ptr( f.as_raw_fd(),
++                                 2,   //offset
++                                 rbuf.as_mut_ptr() as *mut c_void,
++                                 rbuf.len(),
++                                 0,   //priority
++                                 SigevNotify::SigevNone,
++                                 LioOpcode::LIO_NOP)
++        };
++        aiocb.read().unwrap();
++
++        let err = poll_aio(&mut aiocb);
++        assert!(err == Ok(()));
++        assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len());
++    }
++
++    assert!(rbuf == EXPECT);
++}
++
++// Test reading into an immutable buffer.  It should fail
++// FIXME: This test fails to panic on Linux/musl
++#[test]
++#[should_panic(expected = "Can't read into an immutable buffer")]
++#[cfg_attr(target_env = "musl", ignore)]
++fn test_read_immutable_buffer() {
++    let rbuf: &[u8] = b"CDEF";
++    let f = tempfile().unwrap();
++    let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
++                           2,   //offset
++                           rbuf,
++                           0,   //priority
++                           SigevNotify::SigevNone,
++                           LioOpcode::LIO_NOP);
++    aiocb.read().unwrap();
++}
++
++
++// Test a simple aio operation with no completion notification.  We must poll
++// for completion.  Unlike test_aio_read, this test uses AioCb::from_slice
++#[test]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_write() {
++    const INITIAL: &[u8] = b"abcdef123456";
++    let wbuf = "CDEF".to_string().into_bytes();
++    let mut rbuf = Vec::new();
++    const EXPECT: &[u8] = b"abCDEF123456";
++
++    let mut f = tempfile().unwrap();
++    f.write_all(INITIAL).unwrap();
++    let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
++                           2,   //offset
++                           &wbuf,
++                           0,   //priority
++                           SigevNotify::SigevNone,
++                           LioOpcode::LIO_NOP);
++    aiocb.write().unwrap();
++
++    let err = poll_aio(&mut aiocb);
++    assert!(err == Ok(()));
++    assert!(aiocb.aio_return().unwrap() as usize == wbuf.len());
++
++    f.seek(SeekFrom::Start(0)).unwrap();
++    let len = f.read_to_end(&mut rbuf).unwrap();
++    assert!(len == EXPECT.len());
++    assert!(rbuf == EXPECT);
++}
++
++// Tests `AioCb::from_boxed_slice` with `Bytes`
++#[test]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_write_bytes() {
++    const INITIAL: &[u8] = b"abcdef123456";
++    let wbuf = Box::new(Bytes::from(&b"CDEF"[..]));
++    let mut rbuf = Vec::new();
++    const EXPECT: &[u8] = b"abCDEF123456";
++    let expected_len = wbuf.len();
++
++    let mut f = tempfile().unwrap();
++    f.write_all(INITIAL).unwrap();
++    let mut aiocb = AioCb::from_boxed_slice( f.as_raw_fd(),
++                           2,   //offset
++                           wbuf,
++                           0,   //priority
++                           SigevNotify::SigevNone,
++                           LioOpcode::LIO_NOP);
++    aiocb.write().unwrap();
++
++    let err = poll_aio(&mut aiocb);
++    assert!(err == Ok(()));
++    assert!(aiocb.aio_return().unwrap() as usize == expected_len);
++
++    f.seek(SeekFrom::Start(0)).unwrap();
++    let len = f.read_to_end(&mut rbuf).unwrap();
++    assert!(len == EXPECT.len());
++    assert!(rbuf == EXPECT);
++}
++
++// Tests `AioCb::from_boxed_mut_slice` with `BytesMut`
++#[test]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_read_bytes_mut_small() {
++    const INITIAL: &[u8] = b"abcdef";
++    let rbuf = Box::new(BytesMut::from(vec![0; 4]));
++    const EXPECT: &[u8] = b"cdef";
++    let mut f = tempfile().unwrap();
++    f.write_all(INITIAL).unwrap();
++
++    let mut aiocb = AioCb::from_boxed_mut_slice( f.as_raw_fd(),
++                           2,   //offset
++                           rbuf,
++                           0,   //priority
++                           SigevNotify::SigevNone,
++                           LioOpcode::LIO_NOP);
++    aiocb.read().unwrap();
++
++    let err = poll_aio(&mut aiocb);
++    assert_eq!(err, Ok(()));
++    assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len());
++    let buffer = aiocb.boxed_mut_slice().unwrap();
++    assert_eq!(buffer.borrow(), EXPECT);
++}
++
++// Tests `AioCb::from_ptr`
++#[test]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_write_from_pointer() {
++    const INITIAL: &[u8] = b"abcdef123456";
++    let wbuf = "CDEF".to_string().into_bytes();
++    let mut rbuf = Vec::new();
++    const EXPECT: &[u8] = b"abCDEF123456";
++
++    let mut f = tempfile().unwrap();
++    f.write_all(INITIAL).unwrap();
++    // Safety: ok because aiocb outlives poll_aio
++    let mut aiocb = unsafe {
++        AioCb::from_ptr( f.as_raw_fd(),
++                         2,   //offset
++                         wbuf.as_ptr() as *const c_void,
++                         wbuf.len(),
++                         0,   //priority
++                         SigevNotify::SigevNone,
++                         LioOpcode::LIO_NOP)
++    };
++    aiocb.write().unwrap();
++
++    let err = poll_aio(&mut aiocb);
++    assert!(err == Ok(()));
++    assert!(aiocb.aio_return().unwrap() as usize == wbuf.len());
++
++    f.seek(SeekFrom::Start(0)).unwrap();
++    let len = f.read_to_end(&mut rbuf).unwrap();
++    assert!(len == EXPECT.len());
++    assert!(rbuf == EXPECT);
++}
++
++/// `AioCb::write` should not modify the `AioCb` object if `libc::aio_write`
++/// returns an error
++// Skip on Linux, because Linux's AIO implementation can't detect errors
++// synchronously
++#[test]
++#[cfg(any(target_os = "freebsd", target_os = "macos"))]
++fn test_write_error() {
++    let wbuf = "CDEF".to_string().into_bytes();
++    let mut aiocb = AioCb::from_slice( 666, // An invalid file descriptor
++                           0,   //offset
++                           &wbuf,
++                           0,   //priority
++                           SigevNotify::SigevNone,
++                           LioOpcode::LIO_NOP);
++    assert!(aiocb.write().is_err());
++}
++
++lazy_static! {
++    pub static ref SIGNALED: AtomicBool = AtomicBool::new(false);
++}
++
++extern fn sigfunc(_: c_int) {
++    SIGNALED.store(true, Ordering::Relaxed);
++}
++
++// Test an aio operation with completion delivered by a signal
++// FIXME: This test is ignored on mips because of failures in qemu in CI
++#[test]
++#[cfg_attr(any(all(target_env = "musl", target_arch = "x86_64"), target_arch = "mips", target_arch = "mips64"), ignore)]
++fn test_write_sigev_signal() {
++    let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++    let sa = SigAction::new(SigHandler::Handler(sigfunc),
++                            SaFlags::SA_RESETHAND,
++                            SigSet::empty());
++    SIGNALED.store(false, Ordering::Relaxed);
++    unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap();
++
++    const INITIAL: &[u8] = b"abcdef123456";
++    const WBUF: &[u8] = b"CDEF";
++    let mut rbuf = Vec::new();
++    const EXPECT: &[u8] = b"abCDEF123456";
++
++    let mut f = tempfile().unwrap();
++    f.write_all(INITIAL).unwrap();
++    let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
++                           2,   //offset
++                           WBUF,
++                           0,   //priority
++                           SigevNotify::SigevSignal {
++                               signal: Signal::SIGUSR2,
++                               si_value: 0  //TODO: validate in sigfunc
++                           },
++                           LioOpcode::LIO_NOP);
++    aiocb.write().unwrap();
++    while !SIGNALED.load(Ordering::Relaxed) {
++        thread::sleep(time::Duration::from_millis(10));
++    }
++
++    assert!(aiocb.aio_return().unwrap() as usize == WBUF.len());
++    f.seek(SeekFrom::Start(0)).unwrap();
++    let len = f.read_to_end(&mut rbuf).unwrap();
++    assert!(len == EXPECT.len());
++    assert!(rbuf == EXPECT);
++}
++
++// Test LioCb::listio with LIO_WAIT, so all AIO ops should be complete by the
++// time listio returns.
++#[test]
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_liocb_listio_wait() {
++    const INITIAL: &[u8] = b"abcdef123456";
++    const WBUF: &[u8] = b"CDEF";
++    let mut rbuf = vec![0; 4];
++    let rlen = rbuf.len();
++    let mut rbuf2 = Vec::new();
++    const EXPECT: &[u8] = b"abCDEF123456";
++    let mut f = tempfile().unwrap();
++
++    f.write_all(INITIAL).unwrap();
++
++    {
++        let wcb = AioCb::from_slice( f.as_raw_fd(),
++                               2,   //offset
++                               WBUF,
++                               0,   //priority
++                               SigevNotify::SigevNone,
++                               LioOpcode::LIO_WRITE);
++
++        let rcb = AioCb::from_mut_slice( f.as_raw_fd(),
++                                8,   //offset
++                                &mut rbuf,
++                                0,   //priority
++                                SigevNotify::SigevNone,
++                                LioOpcode::LIO_READ);
++        let mut liocb = LioCb::with_capacity(2);
++        liocb.aiocbs.push(wcb);
++        liocb.aiocbs.push(rcb);
++        let err = liocb.listio(LioMode::LIO_WAIT, SigevNotify::SigevNone);
++        err.expect("lio_listio");
++
++        assert!(liocb.aio_return(0).unwrap() as usize == WBUF.len());
++        assert!(liocb.aio_return(1).unwrap() as usize == rlen);
++    }
++    assert!(rbuf.deref().deref() == b"3456");
++
++    f.seek(SeekFrom::Start(0)).unwrap();
++    let len = f.read_to_end(&mut rbuf2).unwrap();
++    assert!(len == EXPECT.len());
++    assert!(rbuf2 == EXPECT);
++}
++
++// Test LioCb::listio with LIO_NOWAIT and no SigEvent, so we must use some other
++// mechanism to check for the individual AioCb's completion.
++#[test]
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++fn test_liocb_listio_nowait() {
++    const INITIAL: &[u8] = b"abcdef123456";
++    const WBUF: &[u8] = b"CDEF";
++    let mut rbuf = vec![0; 4];
++    let rlen = rbuf.len();
++    let mut rbuf2 = Vec::new();
++    const EXPECT: &[u8] = b"abCDEF123456";
++    let mut f = tempfile().unwrap();
++
++    f.write_all(INITIAL).unwrap();
++
++    {
++        let wcb = AioCb::from_slice( f.as_raw_fd(),
++                               2,   //offset
++                               WBUF,
++                               0,   //priority
++                               SigevNotify::SigevNone,
++                               LioOpcode::LIO_WRITE);
++
++        let rcb = AioCb::from_mut_slice( f.as_raw_fd(),
++                                8,   //offset
++                                &mut rbuf,
++                                0,   //priority
++                                SigevNotify::SigevNone,
++                                LioOpcode::LIO_READ);
++        let mut liocb = LioCb::with_capacity(2);
++        liocb.aiocbs.push(wcb);
++        liocb.aiocbs.push(rcb);
++        let err = liocb.listio(LioMode::LIO_NOWAIT, SigevNotify::SigevNone);
++        err.expect("lio_listio");
++
++        poll_aio(&mut liocb.aiocbs[0]).unwrap();
++        poll_aio(&mut liocb.aiocbs[1]).unwrap();
++        assert!(liocb.aiocbs[0].aio_return().unwrap() as usize == WBUF.len());
++        assert!(liocb.aiocbs[1].aio_return().unwrap() as usize == rlen);
++    }
++    assert!(rbuf.deref().deref() == b"3456");
++
++    f.seek(SeekFrom::Start(0)).unwrap();
++    let len = f.read_to_end(&mut rbuf2).unwrap();
++    assert!(len == EXPECT.len());
++    assert!(rbuf2 == EXPECT);
++}
++
++// Test LioCb::listio with LIO_NOWAIT and a SigEvent to indicate when all
++// AioCb's are complete.
++// FIXME: This test is ignored on mips/mips64 because of failures in qemu in CI.
++#[test]
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++#[cfg_attr(any(target_arch = "mips", target_arch = "mips64", target_env = "musl"), ignore)]
++fn test_liocb_listio_signal() {
++    let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++    const INITIAL: &[u8] = b"abcdef123456";
++    const WBUF: &[u8] = b"CDEF";
++    let mut rbuf = vec![0; 4];
++    let rlen = rbuf.len();
++    let mut rbuf2 = Vec::new();
++    const EXPECT: &[u8] = b"abCDEF123456";
++    let mut f = tempfile().unwrap();
++    let sa = SigAction::new(SigHandler::Handler(sigfunc),
++                            SaFlags::SA_RESETHAND,
++                            SigSet::empty());
++    let sigev_notify = SigevNotify::SigevSignal { signal: Signal::SIGUSR2,
++                                                  si_value: 0 };
++
++    f.write_all(INITIAL).unwrap();
++
++    {
++        let wcb = AioCb::from_slice( f.as_raw_fd(),
++                               2,   //offset
++                               WBUF,
++                               0,   //priority
++                               SigevNotify::SigevNone,
++                               LioOpcode::LIO_WRITE);
++
++        let rcb = AioCb::from_mut_slice( f.as_raw_fd(),
++                                8,   //offset
++                                &mut rbuf,
++                                0,   //priority
++                                SigevNotify::SigevNone,
++                                LioOpcode::LIO_READ);
++        let mut liocb = LioCb::with_capacity(2);
++        liocb.aiocbs.push(wcb);
++        liocb.aiocbs.push(rcb);
++        SIGNALED.store(false, Ordering::Relaxed);
++        unsafe { sigaction(Signal::SIGUSR2, &sa) }.unwrap();
++        let err = liocb.listio(LioMode::LIO_NOWAIT, sigev_notify);
++        err.expect("lio_listio");
++        while !SIGNALED.load(Ordering::Relaxed) {
++            thread::sleep(time::Duration::from_millis(10));
++        }
++
++        assert!(liocb.aiocbs[0].aio_return().unwrap() as usize == WBUF.len());
++        assert!(liocb.aiocbs[1].aio_return().unwrap() as usize == rlen);
++    }
++    assert!(rbuf.deref().deref() == b"3456");
++
++    f.seek(SeekFrom::Start(0)).unwrap();
++    let len = f.read_to_end(&mut rbuf2).unwrap();
++    assert!(len == EXPECT.len());
++    assert!(rbuf2 == EXPECT);
++}
++
++// Try to use LioCb::listio to read into an immutable buffer.  It should fail
++// FIXME: This test fails to panic on Linux/musl
++#[test]
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++#[should_panic(expected = "Can't read into an immutable buffer")]
++#[cfg_attr(target_env = "musl", ignore)]
++fn test_liocb_listio_read_immutable() {
++    let rbuf: &[u8] = b"abcd";
++    let f = tempfile().unwrap();
++
++
++    let mut liocb = LioCb::from(vec![
++        AioCb::from_slice( f.as_raw_fd(),
++            2,   //offset
++            rbuf,
++            0,   //priority
++            SigevNotify::SigevNone,
++            LioOpcode::LIO_READ)
++    ]);
++    let _ = liocb.listio(LioMode::LIO_NOWAIT, SigevNotify::SigevNone);
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_aio_drop.rs b/third_party/rust/nix-0.15.0/test/sys/test_aio_drop.rs
+new file mode 100644
+index 0000000000000..492da401ef726
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_aio_drop.rs
+@@ -0,0 +1,32 @@
++extern crate nix;
++extern crate tempfile;
++
++// Test dropping an AioCb that hasn't yet finished.
++// This must happen in its own process, because on OSX this test seems to hose
++// the AIO subsystem and causes subsequent tests to fail
++#[test]
++#[should_panic(expected = "Dropped an in-progress AioCb")]
++#[cfg(all(not(target_env = "musl"),
++          any(target_os = "linux",
++              target_os = "ios",
++              target_os = "macos",
++              target_os = "freebsd",
++              target_os = "netbsd")))]
++fn test_drop() {
++    use nix::sys::aio::*;
++    use nix::sys::signal::*;
++    use std::os::unix::io::AsRawFd;
++    use tempfile::tempfile;
++
++    const WBUF: &[u8] = b"CDEF";
++
++    let f = tempfile().unwrap();
++    f.set_len(6).unwrap();
++    let mut aiocb = AioCb::from_slice( f.as_raw_fd(),
++                           2,   //offset
++                           WBUF,
++                           0,   //priority
++                           SigevNotify::SigevNone,
++                           LioOpcode::LIO_NOP);
++    aiocb.write().unwrap();
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_epoll.rs b/third_party/rust/nix-0.15.0/test/sys/test_epoll.rs
+new file mode 100644
+index 0000000000000..e0dc5131defe0
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_epoll.rs
+@@ -0,0 +1,24 @@
++use nix::sys::epoll::{EpollCreateFlags, EpollFlags, EpollOp, EpollEvent};
++use nix::sys::epoll::{epoll_create1, epoll_ctl};
++use nix::Error;
++use nix::errno::Errno;
++
++#[test]
++pub fn test_epoll_errno() {
++    let efd = epoll_create1(EpollCreateFlags::empty()).unwrap();
++    let result = epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None);
++    assert!(result.is_err());
++    assert_eq!(result.unwrap_err(), Error::Sys(Errno::ENOENT));
++
++    let result = epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, None);
++    assert!(result.is_err());
++    assert_eq!(result.unwrap_err(), Error::Sys(Errno::EINVAL));
++}
++
++#[test]
++pub fn test_epoll_ctl() {
++    let efd = epoll_create1(EpollCreateFlags::empty()).unwrap();
++    let mut event = EpollEvent::new(EpollFlags::EPOLLIN | EpollFlags::EPOLLERR, 1);
++    epoll_ctl(efd, EpollOp::EpollCtlAdd, 1, &mut event).unwrap();
++    epoll_ctl(efd, EpollOp::EpollCtlDel, 1, None).unwrap();
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_inotify.rs b/third_party/rust/nix-0.15.0/test/sys/test_inotify.rs
+new file mode 100644
+index 0000000000000..a8ead46d487ba
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_inotify.rs
+@@ -0,0 +1,65 @@
++use nix::sys::inotify::{AddWatchFlags,InitFlags,Inotify};
++use nix::Error;
++use nix::errno::Errno;
++use tempfile;
++use std::ffi::OsString;
++use std::fs::{rename, File};
++
++#[test]
++pub fn test_inotify() {
++    let instance = Inotify::init(InitFlags::IN_NONBLOCK)
++        .unwrap();
++    let tempdir = tempfile::tempdir().unwrap();
++
++    instance.add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS).unwrap();
++
++    let events = instance.read_events();
++    assert_eq!(events.unwrap_err(), Error::Sys(Errno::EAGAIN));
++
++    File::create(tempdir.path().join("test")).unwrap();
++
++    let events = instance.read_events().unwrap();
++    assert_eq!(events[0].name, Some(OsString::from("test")));
++}
++
++#[test]
++pub fn test_inotify_multi_events() {
++    let instance = Inotify::init(InitFlags::IN_NONBLOCK)
++        .unwrap();
++    let tempdir = tempfile::tempdir().unwrap();
++
++    instance.add_watch(tempdir.path(), AddWatchFlags::IN_ALL_EVENTS).unwrap();
++
++    let events = instance.read_events();
++    assert_eq!(events.unwrap_err(), Error::Sys(Errno::EAGAIN));
++
++    File::create(tempdir.path().join("test")).unwrap();
++    rename(tempdir.path().join("test"), tempdir.path().join("test2")).unwrap();
++
++    // Now there should be 5 events in queue:
++    //   - IN_CREATE on test
++    //   - IN_OPEN on test
++    //   - IN_CLOSE_WRITE on test
++    //   - IN_MOVED_FROM on test with a cookie
++    //   - IN_MOVED_TO on test2 with the same cookie
++
++    let events = instance.read_events().unwrap();
++    assert_eq!(events.len(), 5);
++
++    assert_eq!(events[0].mask, AddWatchFlags::IN_CREATE);
++    assert_eq!(events[0].name, Some(OsString::from("test")));
++
++    assert_eq!(events[1].mask, AddWatchFlags::IN_OPEN);
++    assert_eq!(events[1].name, Some(OsString::from("test")));
++
++    assert_eq!(events[2].mask, AddWatchFlags::IN_CLOSE_WRITE);
++    assert_eq!(events[2].name, Some(OsString::from("test")));
++
++    assert_eq!(events[3].mask, AddWatchFlags::IN_MOVED_FROM);
++    assert_eq!(events[3].name, Some(OsString::from("test")));
++
++    assert_eq!(events[4].mask, AddWatchFlags::IN_MOVED_TO);
++    assert_eq!(events[4].name, Some(OsString::from("test2")));
++
++    assert_eq!(events[3].cookie, events[4].cookie);
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_ioctl.rs b/third_party/rust/nix-0.15.0/test/sys/test_ioctl.rs
+new file mode 100644
+index 0000000000000..0a439b3346f53
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_ioctl.rs
+@@ -0,0 +1,334 @@
++#![allow(dead_code)]
++
++// Simple tests to ensure macro generated fns compile
++ioctl_none_bad!(do_bad, 0x1234);
++ioctl_read_bad!(do_bad_read, 0x1234, u16);
++ioctl_write_int_bad!(do_bad_write_int, 0x1234);
++ioctl_write_ptr_bad!(do_bad_write_ptr, 0x1234, u8);
++ioctl_readwrite_bad!(do_bad_readwrite, 0x1234, u32);
++ioctl_none!(do_none, 0, 0);
++ioctl_read!(read_test, 0, 0, u32);
++ioctl_write_int!(write_ptr_int, 0, 0);
++ioctl_write_ptr!(write_ptr_u8, 0, 0, u8);
++ioctl_write_ptr!(write_ptr_u32, 0, 0, u32);
++ioctl_write_ptr!(write_ptr_u64, 0, 0, u64);
++ioctl_readwrite!(readwrite_test, 0, 0, u64);
++ioctl_read_buf!(readbuf_test, 0, 0, u32);
++const SPI_IOC_MAGIC: u8 = b'k';
++const SPI_IOC_MESSAGE: u8 = 0;
++ioctl_write_buf!(writebuf_test_consts, SPI_IOC_MAGIC, SPI_IOC_MESSAGE, u8);
++ioctl_write_buf!(writebuf_test_u8, 0, 0, u8);
++ioctl_write_buf!(writebuf_test_u32, 0, 0, u32);
++ioctl_write_buf!(writebuf_test_u64, 0, 0, u64);
++ioctl_readwrite_buf!(readwritebuf_test, 0, 0, u32);
++
++// See C code for source of values for op calculations (does NOT work for mips/powerpc):
++// https://gist.github.com/posborne/83ea6880770a1aef332e
++//
++// TODO:  Need a way to compute these constants at test time.  Using precomputed
++// values is fragile and needs to be maintained.
++
++#[cfg(any(target_os = "linux", target_os = "android"))]
++mod linux {
++    #[test]
++    fn test_op_none() {
++        if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){
++            assert_eq!(request_code_none!(b'q', 10), 0x2000_710A);
++            assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF);
++        } else {
++            assert_eq!(request_code_none!(b'q', 10), 0x0000_710A);
++            assert_eq!(request_code_none!(b'a', 255), 0x0000_61FF);
++        }
++    }
++
++    #[test]
++    fn test_op_write() {
++        if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){
++            assert_eq!(request_code_write!(b'z', 10, 1), 0x8001_7A0A);
++            assert_eq!(request_code_write!(b'z', 10, 512), 0x8200_7A0A);
++        } else {
++            assert_eq!(request_code_write!(b'z', 10, 1), 0x4001_7A0A);
++            assert_eq!(request_code_write!(b'z', 10, 512), 0x4200_7A0A);
++        }
++    }
++
++    #[cfg(target_pointer_width = "64")]
++    #[test]
++    fn test_op_write_64() {
++        if cfg!(any(target_arch = "mips64", target_arch="powerpc64")){
++            assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A);
++        } else {
++            assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A);
++        }
++
++    }
++
++    #[test]
++    fn test_op_read() {
++        if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){
++            assert_eq!(request_code_read!(b'z', 10, 1), 0x4001_7A0A);
++            assert_eq!(request_code_read!(b'z', 10, 512), 0x4200_7A0A);
++        } else {
++            assert_eq!(request_code_read!(b'z', 10, 1), 0x8001_7A0A);
++            assert_eq!(request_code_read!(b'z', 10, 512), 0x8200_7A0A);
++        }
++    }
++
++    #[cfg(target_pointer_width = "64")]
++    #[test]
++    fn test_op_read_64() {
++        if cfg!(any(target_arch = "mips64", target_arch="powerpc64")){
++            assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A);
++        } else {
++            assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A);
++        }
++    }
++
++    #[test]
++    fn test_op_read_write() {
++        assert_eq!(request_code_readwrite!(b'z', 10, 1), 0xC001_7A0A);
++        assert_eq!(request_code_readwrite!(b'z', 10, 512), 0xC200_7A0A);
++    }
++
++    #[cfg(target_pointer_width = "64")]
++    #[test]
++    fn test_op_read_write_64() {
++        assert_eq!(request_code_readwrite!(b'z', 10, (1 as u64) << 32), 0xC000_7A0A);
++    }
++}
++
++#[cfg(any(target_os = "dragonfly",
++          target_os = "freebsd",
++          target_os = "ios",
++          target_os = "macos",
++          target_os = "netbsd",
++          target_os = "openbsd"))]
++mod bsd {
++    #[test]
++    fn test_op_none() {
++        assert_eq!(request_code_none!(b'q', 10), 0x2000_710A);
++        assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF);
++    }
++
++    #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
++    #[test]
++    fn test_op_write_int() {
++        assert_eq!(request_code_write_int!(b'v', 4), 0x2004_7604);
++        assert_eq!(request_code_write_int!(b'p', 2), 0x2004_7002);
++    }
++
++    #[test]
++    fn test_op_write() {
++        assert_eq!(request_code_write!(b'z', 10, 1), 0x8001_7A0A);
++        assert_eq!(request_code_write!(b'z', 10, 512), 0x8200_7A0A);
++    }
++
++    #[cfg(target_pointer_width = "64")]
++    #[test]
++    fn test_op_write_64() {
++        assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A);
++    }
++
++    #[test]
++    fn test_op_read() {
++        assert_eq!(request_code_read!(b'z', 10, 1), 0x4001_7A0A);
++        assert_eq!(request_code_read!(b'z', 10, 512), 0x4200_7A0A);
++    }
++
++    #[cfg(target_pointer_width = "64")]
++    #[test]
++    fn test_op_read_64() {
++        assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A);
++    }
++
++    #[test]
++    fn test_op_read_write() {
++        assert_eq!(request_code_readwrite!(b'z', 10, 1), 0xC001_7A0A);
++        assert_eq!(request_code_readwrite!(b'z', 10, 512), 0xC200_7A0A);
++    }
++
++    #[cfg(target_pointer_width = "64")]
++    #[test]
++    fn test_op_read_write_64() {
++        assert_eq!(request_code_readwrite!(b'z', 10, (1 as u64) << 32), 0xC000_7A0A);
++    }
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++mod linux_ioctls {
++    use std::mem;
++    use std::os::unix::io::AsRawFd;
++
++    use tempfile::tempfile;
++    use libc::{TCGETS, TCSBRK, TCSETS, TIOCNXCL, termios};
++
++    use nix::Error::Sys;
++    use nix::errno::Errno::{ENOTTY, ENOSYS};
++
++    ioctl_none_bad!(tiocnxcl, TIOCNXCL);
++    #[test]
++    fn test_ioctl_none_bad() {
++        let file = tempfile().unwrap();
++        let res = unsafe { tiocnxcl(file.as_raw_fd()) };
++        assert_eq!(res, Err(Sys(ENOTTY)));
++    }
++
++    ioctl_read_bad!(tcgets, TCGETS, termios);
++    #[test]
++    fn test_ioctl_read_bad() {
++        let file = tempfile().unwrap();
++        let mut termios = unsafe { mem::uninitialized() };
++        let res = unsafe { tcgets(file.as_raw_fd(), &mut termios) };
++        assert_eq!(res, Err(Sys(ENOTTY)));
++    }
++
++    ioctl_write_int_bad!(tcsbrk, TCSBRK);
++    #[test]
++    fn test_ioctl_write_int_bad() {
++        let file = tempfile().unwrap();
++        let res = unsafe { tcsbrk(file.as_raw_fd(), 0) };
++        assert_eq!(res, Err(Sys(ENOTTY)));
++    }
++
++    ioctl_write_ptr_bad!(tcsets, TCSETS, termios);
++    #[test]
++    fn test_ioctl_write_ptr_bad() {
++        let file = tempfile().unwrap();
++        let termios: termios = unsafe { mem::uninitialized() };
++        let res = unsafe { tcsets(file.as_raw_fd(), &termios) };
++        assert_eq!(res, Err(Sys(ENOTTY)));
++    }
++
++    // FIXME: Find a suitable example for `ioctl_readwrite_bad`
++
++    // From linux/videodev2.h
++    ioctl_none!(log_status, b'V', 70);
++    #[test]
++    fn test_ioctl_none() {
++        let file = tempfile().unwrap();
++        let res = unsafe { log_status(file.as_raw_fd()) };
++        assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
++    }
++
++    #[repr(C)]
++    pub struct v4l2_audio {
++        index: u32,
++        name: [u8; 32],
++        capability: u32,
++        mode: u32,
++        reserved: [u32; 2],
++    }
++
++    // From linux/videodev2.h
++    ioctl_write_ptr!(s_audio, b'V', 34, v4l2_audio);
++    #[test]
++    fn test_ioctl_write_ptr() {
++        let file = tempfile().unwrap();
++        let data: v4l2_audio = unsafe { mem::zeroed() };
++        let res = unsafe { s_audio(file.as_raw_fd(), &data) };
++        assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
++    }
++
++    // From linux/net/bluetooth/hci_sock.h
++    const HCI_IOC_MAGIC: u8 = b'H';
++    const HCI_IOC_HCIDEVUP: u8 = 201;
++    ioctl_write_int!(hcidevup, HCI_IOC_MAGIC, HCI_IOC_HCIDEVUP);
++    #[test]
++    fn test_ioctl_write_int() {
++        let file = tempfile().unwrap();
++        let res = unsafe { hcidevup(file.as_raw_fd(), 0) };
++        assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
++    }
++
++    // From linux/videodev2.h
++    ioctl_read!(g_audio, b'V', 33, v4l2_audio);
++    #[test]
++    fn test_ioctl_read() {
++        let file = tempfile().unwrap();
++        let mut data: v4l2_audio = unsafe { mem::uninitialized() };
++        let res = unsafe { g_audio(file.as_raw_fd(), &mut data) };
++        assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
++    }
++
++    // From linux/videodev2.h
++    ioctl_readwrite!(enum_audio,  b'V', 65, v4l2_audio);
++    #[test]
++    fn test_ioctl_readwrite() {
++        let file = tempfile().unwrap();
++        let mut data: v4l2_audio = unsafe { mem::uninitialized() };
++        let res = unsafe { enum_audio(file.as_raw_fd(), &mut data) };
++        assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
++    }
++
++    // FIXME: Find a suitable example for `ioctl_read_buf`.
++
++    #[repr(C)]
++    pub struct spi_ioc_transfer {
++        tx_buf: u64,
++        rx_buf: u64,
++        len: u32,
++        speed_hz: u32,
++        delay_usecs: u16,
++        bits_per_word: u8,
++        cs_change: u8,
++        tx_nbits: u8,
++        rx_nbits: u8,
++        pad: u16,
++    }
++
++    // From linux/spi/spidev.h
++    ioctl_write_buf!(spi_ioc_message, super::SPI_IOC_MAGIC, super::SPI_IOC_MESSAGE, spi_ioc_transfer);
++    #[test]
++    fn test_ioctl_write_buf() {
++        let file = tempfile().unwrap();
++        let data: [spi_ioc_transfer; 4] = unsafe { mem::zeroed() };
++        let res = unsafe { spi_ioc_message(file.as_raw_fd(), &data[..]) };
++        assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
++    }
++
++    // FIXME: Find a suitable example for `ioctl_readwrite_buf`.
++}
++
++#[cfg(target_os = "freebsd")]
++mod freebsd_ioctls {
++    use std::mem;
++    use std::os::unix::io::AsRawFd;
++
++    use tempfile::tempfile;
++    use libc::termios;
++
++    use nix::Error::Sys;
++    use nix::errno::Errno::ENOTTY;
++
++    // From sys/sys/ttycom.h
++    const TTY_IOC_MAGIC: u8 = b't';
++    const TTY_IOC_TYPE_NXCL: u8 = 14;
++    const TTY_IOC_TYPE_GETA: u8 = 19;
++    const TTY_IOC_TYPE_SETA: u8 = 20;
++
++    ioctl_none!(tiocnxcl, TTY_IOC_MAGIC, TTY_IOC_TYPE_NXCL);
++    #[test]
++    fn test_ioctl_none() {
++        let file = tempfile().unwrap();
++        let res = unsafe { tiocnxcl(file.as_raw_fd()) };
++        assert_eq!(res, Err(Sys(ENOTTY)));
++    }
++
++    ioctl_read!(tiocgeta, TTY_IOC_MAGIC, TTY_IOC_TYPE_GETA, termios);
++    #[test]
++    fn test_ioctl_read() {
++        let file = tempfile().unwrap();
++        let mut termios = unsafe { mem::uninitialized() };
++        let res = unsafe { tiocgeta(file.as_raw_fd(), &mut termios) };
++        assert_eq!(res, Err(Sys(ENOTTY)));
++    }
++
++    ioctl_write_ptr!(tiocseta, TTY_IOC_MAGIC, TTY_IOC_TYPE_SETA, termios);
++    #[test]
++    fn test_ioctl_write_ptr() {
++        let file = tempfile().unwrap();
++        let termios: termios = unsafe { mem::uninitialized() };
++        let res = unsafe { tiocseta(file.as_raw_fd(), &termios) };
++        assert_eq!(res, Err(Sys(ENOTTY)));
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_lio_listio_resubmit.rs b/third_party/rust/nix-0.15.0/test/sys/test_lio_listio_resubmit.rs
+new file mode 100644
+index 0000000000000..19ee3facf87d7
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_lio_listio_resubmit.rs
+@@ -0,0 +1,111 @@
++// vim: tw=80
++
++// Annoyingly, Cargo is unable to conditionally build an entire test binary.  So
++// we must disable the test here rather than in Cargo.toml
++#![cfg(target_os = "freebsd")]
++
++extern crate nix;
++extern crate sysctl;
++extern crate tempfile;
++
++use nix::Error;
++use nix::errno::*;
++use nix::libc::off_t;
++use nix::sys::aio::*;
++use nix::sys::signal::SigevNotify;
++use nix::unistd::{SysconfVar, sysconf};
++use std::os::unix::io::AsRawFd;
++use std::{thread, time};
++use sysctl::CtlValue;
++use tempfile::tempfile;
++
++const BYTES_PER_OP: usize = 512;
++
++/// Attempt to collect final status for all of `liocb`'s operations, freeing
++/// system resources
++fn finish_liocb(liocb: &mut LioCb) {
++    for j in 0..liocb.aiocbs.len() {
++        loop {
++            let e = liocb.error(j);
++            match e {
++                Ok(()) => break,
++                Err(Error::Sys(Errno::EINPROGRESS)) =>
++                    thread::sleep(time::Duration::from_millis(10)),
++                Err(x) => panic!("aio_error({:?})", x)
++            }
++        }
++        assert_eq!(liocb.aio_return(j).unwrap(), BYTES_PER_OP as isize);
++    }
++}
++
++// Deliberately exceed system resource limits, causing lio_listio to return EIO.
++// This test must run in its own process since it deliberately uses all AIO
++// resources.  ATM it is only enabled on FreeBSD, because I don't know how to
++// check system AIO limits on other operating systems.
++#[test]
++fn test_lio_listio_resubmit() {
++    let mut resubmit_count = 0;
++
++    // Lookup system resource limits
++    let alm = sysconf(SysconfVar::AIO_LISTIO_MAX)
++        .expect("sysconf").unwrap() as usize;
++    let maqpp = if let CtlValue::Int(x) = sysctl::value(
++            "vfs.aio.max_aio_queue_per_proc").unwrap(){
++        x as usize
++    } else {
++        panic!("unknown sysctl");
++    };
++
++    // Find lio_listio sizes that satisfy the AIO_LISTIO_MAX constraint and also
++    // result in a final lio_listio call that can only partially be queued
++    let target_ops = maqpp + alm / 2;
++    let num_listios = (target_ops + alm - 3) / (alm - 2);
++    let ops_per_listio = (target_ops + num_listios - 1) / num_listios;
++    assert!((num_listios - 1) * ops_per_listio < maqpp,
++        "the last lio_listio won't make any progress; fix the algorithm");
++    println!("Using {:?} LioCbs of {:?} operations apiece", num_listios,
++             ops_per_listio);
++
++    let f = tempfile().unwrap();
++    let buffer_set = (0..num_listios).map(|_| {
++        (0..ops_per_listio).map(|_| {
++            vec![0u8; BYTES_PER_OP]
++        }).collect::<Vec<_>>()
++    }).collect::<Vec<_>>();
++
++    let mut liocbs = (0..num_listios).map(|i| {
++        let mut liocb = LioCb::with_capacity(ops_per_listio);
++        for j in 0..ops_per_listio {
++            let offset = (BYTES_PER_OP * (i * ops_per_listio + j)) as off_t;
++            let wcb = AioCb::from_slice( f.as_raw_fd(),
++                                   offset,
++                                   &buffer_set[i][j][..],
++                                   0,   //priority
++                                   SigevNotify::SigevNone,
++                                   LioOpcode::LIO_WRITE);
++            liocb.aiocbs.push(wcb);
++        }
++        let mut err = liocb.listio(LioMode::LIO_NOWAIT, SigevNotify::SigevNone);
++        while err == Err(Error::Sys(Errno::EIO)) ||
++              err == Err(Error::Sys(Errno::EAGAIN)) ||
++              err == Err(Error::Sys(Errno::EINTR)) {
++            // 
++            thread::sleep(time::Duration::from_millis(10));
++            resubmit_count += 1;
++            err = liocb.listio_resubmit(LioMode::LIO_NOWAIT,
++                                        SigevNotify::SigevNone);
++        }
++        liocb
++    }).collect::<Vec<_>>();
++
++    // Ensure that every AioCb completed
++    for liocb in liocbs.iter_mut() {
++        finish_liocb(liocb);
++    }
++
++    if resubmit_count > 0 {
++        println!("Resubmitted {:?} times, test passed", resubmit_count);
++    } else {
++        println!("Never resubmitted.  Test ambiguous");
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_pthread.rs b/third_party/rust/nix-0.15.0/test/sys/test_pthread.rs
+new file mode 100644
+index 0000000000000..8928010087a13
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_pthread.rs
+@@ -0,0 +1,15 @@
++use nix::sys::pthread::*;
++
++#[cfg(target_env = "musl")]
++#[test]
++fn test_pthread_self() {
++    let tid = pthread_self();
++    assert!(tid != ::std::ptr::null_mut());
++}
++
++#[cfg(not(target_env = "musl"))]
++#[test]
++fn test_pthread_self() {
++    let tid = pthread_self();
++    assert!(tid != 0);
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_ptrace.rs b/third_party/rust/nix-0.15.0/test/sys/test_ptrace.rs
+new file mode 100644
+index 0000000000000..24d9b522ee4e5
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_ptrace.rs
+@@ -0,0 +1,107 @@
++use nix::Error;
++use nix::errno::Errno;
++use nix::unistd::getpid;
++use nix::sys::ptrace;
++#[cfg(any(target_os = "android", target_os = "linux"))]
++use nix::sys::ptrace::Options;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++use std::mem;
++
++#[test]
++fn test_ptrace() {
++    // Just make sure ptrace can be called at all, for now.
++    // FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS
++    let err = ptrace::attach(getpid()).unwrap_err();
++    assert!(err == Error::Sys(Errno::EPERM) || err == Error::Sys(Errno::EINVAL) ||
++            err == Error::Sys(Errno::ENOSYS));
++}
++
++// Just make sure ptrace_setoptions can be called at all, for now.
++#[test]
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn test_ptrace_setoptions() {
++    let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD).unwrap_err();
++    assert!(err != Error::UnsupportedOperation);
++}
++
++// Just make sure ptrace_getevent can be called at all, for now.
++#[test]
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn test_ptrace_getevent() {
++    let err = ptrace::getevent(getpid()).unwrap_err();
++    assert!(err != Error::UnsupportedOperation);
++}
++
++// Just make sure ptrace_getsiginfo can be called at all, for now.
++#[test]
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn test_ptrace_getsiginfo() {
++    if let Err(Error::UnsupportedOperation) = ptrace::getsiginfo(getpid()) {
++        panic!("ptrace_getsiginfo returns Error::UnsupportedOperation!");
++    }
++}
++
++// Just make sure ptrace_setsiginfo can be called at all, for now.
++#[test]
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn test_ptrace_setsiginfo() {
++    let siginfo = unsafe { mem::uninitialized() };
++    if let Err(Error::UnsupportedOperation) = ptrace::setsiginfo(getpid(), &siginfo) {
++        panic!("ptrace_setsiginfo returns Error::UnsupportedOperation!");
++    }
++}
++
++
++#[test]
++fn test_ptrace_cont() {
++    use nix::sys::ptrace;
++    use nix::sys::signal::{raise, Signal};
++    use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus};
++    use nix::unistd::fork;
++    use nix::unistd::ForkResult::*;
++
++    let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++
++    // FIXME: qemu-user doesn't implement ptrace on all architectures
++    // and retunrs ENOSYS in this case.
++    // We (ab)use this behavior to detect the affected platforms
++    // and skip the test then.
++    // On valid platforms the ptrace call should return Errno::EPERM, this
++    // is already tested by `test_ptrace`.
++    let err = ptrace::attach(getpid()).unwrap_err();
++    if err == Error::Sys(Errno::ENOSYS) {
++        return;
++    }
++
++    match fork().expect("Error: Fork Failed") {
++        Child => {
++            ptrace::traceme().unwrap();
++            // As recommended by ptrace(2), raise SIGTRAP to pause the child
++            // until the parent is ready to continue
++            loop {
++                raise(Signal::SIGTRAP).unwrap();
++            }
++
++        },
++        Parent { child } => {
++            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)));
++            ptrace::cont(child, None).unwrap();
++            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTRAP)));
++            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 
++                    // 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.
++                    let _ = waitpid(child, Some(WaitPidFlag::WNOHANG));
++                    while ptrace::cont(child, Some(Signal::SIGKILL)).is_ok() {
++                        let _ = waitpid(child, Some(WaitPidFlag::WNOHANG));
++                    }
++                }
++                _ => panic!("The process should have been killed"),
++            }
++        },
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_select.rs b/third_party/rust/nix-0.15.0/test/sys/test_select.rs
+new file mode 100644
+index 0000000000000..cf68700c5e16f
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_select.rs
+@@ -0,0 +1,54 @@
++use nix::sys::select::*;
++use nix::unistd::{pipe, write};
++use nix::sys::signal::SigSet;
++use nix::sys::time::{TimeSpec, TimeValLike};
++
++#[test]
++pub fn test_pselect() {
++    let _mtx = ::SIGNAL_MTX
++        .lock()
++        .expect("Mutex got poisoned by another test");
++
++    let (r1, w1) = pipe().unwrap();
++    write(w1, b"hi!").unwrap();
++    let (r2, _w2) = pipe().unwrap();
++
++    let mut fd_set = FdSet::new();
++    fd_set.insert(r1);
++    fd_set.insert(r2);
++
++    let timeout = TimeSpec::seconds(10);
++    let sigmask = SigSet::empty();
++    assert_eq!(
++        1,
++        pselect(None, &mut fd_set, None, None, &timeout, &sigmask).unwrap()
++    );
++    assert!(fd_set.contains(r1));
++    assert!(!fd_set.contains(r2));
++}
++
++#[test]
++pub fn test_pselect_nfds2() {
++    let (r1, w1) = pipe().unwrap();
++    write(w1, b"hi!").unwrap();
++    let (r2, _w2) = pipe().unwrap();
++
++    let mut fd_set = FdSet::new();
++    fd_set.insert(r1);
++    fd_set.insert(r2);
++
++    let timeout = TimeSpec::seconds(10);
++    assert_eq!(
++        1,
++        pselect(
++            ::std::cmp::max(r1, r2) + 1,
++            &mut fd_set,
++            None,
++            None,
++            &timeout,
++            None
++        ).unwrap()
++    );
++    assert!(fd_set.contains(r1));
++    assert!(!fd_set.contains(r2));
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_signal.rs b/third_party/rust/nix-0.15.0/test/sys/test_signal.rs
+new file mode 100644
+index 0000000000000..8780763f773ef
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_signal.rs
+@@ -0,0 +1,104 @@
++use libc;
++use nix::Error;
++use nix::sys::signal::*;
++use nix::unistd::*;
++use std::sync::atomic::{AtomicBool, Ordering};
++
++#[test]
++fn test_kill_none() {
++    kill(getpid(), None).expect("Should be able to send signal to myself.");
++}
++
++#[test]
++fn test_killpg_none() {
++    killpg(getpgrp(), None)
++        .expect("Should be able to send signal to my process group.");
++}
++
++#[test]
++fn test_old_sigaction_flags() {
++    extern "C" fn handler(_: ::libc::c_int) {}
++    let act = SigAction::new(
++        SigHandler::Handler(handler),
++        SaFlags::empty(),
++        SigSet::empty(),
++    );
++    let oact = unsafe { sigaction(SIGINT, &act) }.unwrap();
++    let _flags = oact.flags();
++    let oact = unsafe { sigaction(SIGINT, &act) }.unwrap();
++    let _flags = oact.flags();
++}
++
++#[test]
++fn test_sigprocmask_noop() {
++    sigprocmask(SigmaskHow::SIG_BLOCK, None, None)
++        .expect("this should be an effective noop");
++}
++
++#[test]
++fn test_sigprocmask() {
++    let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++
++    // This needs to be a signal that rust doesn't use in the test harness.
++    const SIGNAL: Signal = Signal::SIGCHLD;
++
++    let mut old_signal_set = SigSet::empty();
++    sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set))
++        .expect("expect to be able to retrieve old signals");
++
++    // Make sure the old set doesn't contain the signal, otherwise the following
++    // test don't make sense.
++    assert_eq!(old_signal_set.contains(SIGNAL), false,
++               "the {:?} signal is already blocked, please change to a \
++                different one", SIGNAL);
++
++    // Now block the signal.
++    let mut signal_set = SigSet::empty();
++    signal_set.add(SIGNAL);
++    sigprocmask(SigmaskHow::SIG_BLOCK, Some(&signal_set), None)
++        .expect("expect to be able to block signals");
++
++    // And test it again, to make sure the change was effective.
++    old_signal_set.clear();
++    sigprocmask(SigmaskHow::SIG_BLOCK, None, Some(&mut old_signal_set))
++        .expect("expect to be able to retrieve old signals");
++    assert_eq!(old_signal_set.contains(SIGNAL), true,
++               "expected the {:?} to be blocked", SIGNAL);
++
++    // Reset the signal.
++    sigprocmask(SigmaskHow::SIG_UNBLOCK, Some(&signal_set), None)
++        .expect("expect to be able to block signals");
++}
++
++lazy_static! {
++    static ref SIGNALED: AtomicBool = AtomicBool::new(false);
++}
++
++extern fn test_sigaction_handler(signal: libc::c_int) {
++    let signal = Signal::from_c_int(signal).unwrap();
++    SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed);
++}
++
++extern fn test_sigaction_action(_: libc::c_int, _: *mut libc::siginfo_t, _: *mut libc::c_void) {
++}
++
++#[test]
++fn test_signal() {
++    let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++
++    unsafe { signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap();
++    raise(Signal::SIGINT).unwrap();
++    assert_eq!(unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), SigHandler::SigIgn);
++
++    let handler = SigHandler::Handler(test_sigaction_handler);
++    assert_eq!(unsafe { signal(Signal::SIGINT, handler) }.unwrap(), SigHandler::SigDfl);
++    raise(Signal::SIGINT).unwrap();
++    assert!(SIGNALED.load(Ordering::Relaxed));
++    assert_eq!(unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), handler);
++
++    let action_handler = SigHandler::SigAction(test_sigaction_action);
++    assert_eq!(unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(), Error::UnsupportedOperation);
++
++    // Restore default signal handler
++    unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap();
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_signalfd.rs b/third_party/rust/nix-0.15.0/test/sys/test_signalfd.rs
+new file mode 100644
+index 0000000000000..a3b6098841f1c
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_signalfd.rs
+@@ -0,0 +1,25 @@
++#[test]
++fn test_signalfd() {
++    use nix::sys::signalfd::SignalFd;
++    use nix::sys::signal::{self, raise, Signal, SigSet};
++
++    // Grab the mutex for altering signals so we don't interfere with other tests.
++    let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++
++    // Block the SIGUSR1 signal from automatic processing for this thread
++    let mut mask = SigSet::empty();
++    mask.add(signal::SIGUSR1);
++    mask.thread_block().unwrap();
++
++    let mut fd = SignalFd::new(&mask).unwrap();
++
++    // Send a SIGUSR1 signal to the current process. Note that this uses `raise` instead of `kill`
++    // because `kill` with `getpid` isn't correct during multi-threaded execution like during a
++    // cargo test session. Instead use `raise` which does the correct thing by default.
++    raise(signal::SIGUSR1).expect("Error: raise(SIGUSR1) failed");
++
++    // And now catch that same signal.
++    let res = fd.read_signal().unwrap().unwrap();
++    let signo = Signal::from_c_int(res.ssi_signo as i32).unwrap();
++    assert_eq!(signo, signal::SIGUSR1);
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_socket.rs b/third_party/rust/nix-0.15.0/test/sys/test_socket.rs
+new file mode 100644
+index 0000000000000..7e64d2b77f071
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_socket.rs
+@@ -0,0 +1,1066 @@
++use nix::ifaddrs::InterfaceAddress;
++use nix::sys::socket::{AddressFamily, InetAddr, UnixAddr, getsockname};
++use std::collections::hash_map::DefaultHasher;
++use std::hash::{Hash, Hasher};
++use std::net::{self, Ipv6Addr, SocketAddr, SocketAddrV6};
++use std::os::unix::io::RawFd;
++use std::path::Path;
++use std::slice;
++use std::str::FromStr;
++use libc::c_char;
++use tempfile;
++
++#[test]
++pub fn test_inetv4_addr_to_sock_addr() {
++    let actual: net::SocketAddr = FromStr::from_str("127.0.0.1:3000").unwrap();
++    let addr = InetAddr::from_std(&actual);
++
++    match addr {
++        InetAddr::V4(addr) => {
++            let ip: u32 = 0x7f00_0001;
++            let port: u16 = 3000;
++            let saddr = addr.sin_addr.s_addr;
++
++            assert_eq!(saddr, ip.to_be());
++            assert_eq!(addr.sin_port, port.to_be());
++        }
++        _ => panic!("nope"),
++    }
++
++    assert_eq!(addr.to_str(), "127.0.0.1:3000");
++
++    let inet = addr.to_std();
++    assert_eq!(actual, inet);
++}
++
++#[test]
++pub fn test_inetv6_addr_to_sock_addr() {
++    let port: u16 = 3000;
++    let flowinfo: u32 = 1;
++    let scope_id: u32 = 2;
++    let ip: Ipv6Addr = "fe80::1".parse().unwrap();
++
++    let actual = SocketAddr::V6(SocketAddrV6::new(ip, port, flowinfo, scope_id));
++    let addr = InetAddr::from_std(&actual);
++
++    match addr {
++        InetAddr::V6(addr) => {
++            assert_eq!(addr.sin6_port, port.to_be());
++            assert_eq!(addr.sin6_flowinfo, flowinfo);
++            assert_eq!(addr.sin6_scope_id, scope_id);
++        }
++        _ => panic!("nope"),
++    }
++
++    assert_eq!(actual, addr.to_std());
++}
++
++#[test]
++pub fn test_path_to_sock_addr() {
++    let path = "/foo/bar";
++    let actual = Path::new(path);
++    let addr = UnixAddr::new(actual).unwrap();
++
++    let expect: &[c_char] = unsafe {
++        slice::from_raw_parts(path.as_bytes().as_ptr() as *const c_char, path.len())
++    };
++    assert_eq!(&addr.0.sun_path[..8], expect);
++
++    assert_eq!(addr.path(), Some(actual));
++}
++
++fn calculate_hash<T: Hash>(t: &T) -> u64 {
++    let mut s = DefaultHasher::new();
++    t.hash(&mut s);
++    s.finish()
++}
++
++#[test]
++pub fn test_addr_equality_path() {
++    let path = "/foo/bar";
++    let actual = Path::new(path);
++    let addr1 = UnixAddr::new(actual).unwrap();
++    let mut addr2 = addr1.clone();
++
++    addr2.0.sun_path[10] = 127;
++
++    assert_eq!(addr1, addr2);
++    assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2));
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++#[test]
++pub fn test_abstract_sun_path_too_long() {
++    let name = String::from("nix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0tesnix\0abstract\0testttttnix\0abstract\0test\0make\0sure\0this\0is\0long\0enough");
++    let addr = UnixAddr::new_abstract(name.as_bytes());
++    assert!(addr.is_err());
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++#[test]
++pub fn test_addr_equality_abstract() {
++    let name = String::from("nix\0abstract\0test");
++    let addr1 = UnixAddr::new_abstract(name.as_bytes()).unwrap();
++    let mut addr2 = addr1.clone();
++
++    assert_eq!(addr1, addr2);
++    assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2));
++
++    addr2.0.sun_path[18] = 127;
++    assert_ne!(addr1, addr2);
++    assert_ne!(calculate_hash(&addr1), calculate_hash(&addr2));
++}
++
++// Test getting/setting abstract addresses (without unix socket creation)
++#[cfg(target_os = "linux")]
++#[test]
++pub fn test_abstract_uds_addr() {
++    let empty = String::new();
++    let addr = UnixAddr::new_abstract(empty.as_bytes()).unwrap();
++    let sun_path = [0u8; 107];
++    assert_eq!(addr.as_abstract(), Some(&sun_path[..]));
++
++    let name = String::from("nix\0abstract\0test");
++    let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap();
++    let sun_path = [
++        110u8, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116, 0, 0, 0, 0,
++        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++    ];
++    assert_eq!(addr.as_abstract(), Some(&sun_path[..]));
++    assert_eq!(addr.path(), None);
++
++    // Internally, name is null-prefixed (abstract namespace)
++    assert_eq!(addr.0.sun_path[0], 0);
++}
++
++#[test]
++pub fn test_getsockname() {
++    use nix::sys::socket::{socket, AddressFamily, SockType, SockFlag};
++    use nix::sys::socket::{bind, SockAddr};
++
++    let tempdir = tempfile::tempdir().unwrap();
++    let sockname = tempdir.path().join("sock");
++    let sock = socket(AddressFamily::Unix, SockType::Stream, SockFlag::empty(), None)
++               .expect("socket failed");
++    let sockaddr = SockAddr::new_unix(&sockname).unwrap();
++    bind(sock, &sockaddr).expect("bind failed");
++    assert_eq!(sockaddr.to_str(),
++               getsockname(sock).expect("getsockname failed").to_str());
++}
++
++#[test]
++pub fn test_socketpair() {
++    use nix::unistd::{read, write};
++    use nix::sys::socket::{socketpair, AddressFamily, SockType, SockFlag};
++
++    let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty())
++                     .unwrap();
++    write(fd1, b"hello").unwrap();
++    let mut buf = [0;5];
++    read(fd2, &mut buf).unwrap();
++
++    assert_eq!(&buf[..], b"hello");
++}
++
++// Test error handling of our recvmsg wrapper
++#[test]
++pub fn test_recvmsg_ebadf() {
++    use nix::Error;
++    use nix::errno::Errno;
++    use nix::sys::socket::{MsgFlags, recvmsg};
++    use nix::sys::uio::IoVec;
++
++    let mut buf = [0u8; 5];
++    let iov = [IoVec::from_mut_slice(&mut buf[..])];
++    let fd = -1;    // Bad file descriptor
++    let r = recvmsg(fd, &iov, None, MsgFlags::empty());
++    assert_eq!(r.err().unwrap(), Error::Sys(Errno::EBADF));
++}
++
++// Disable the test on emulated platforms due to a bug in QEMU versions <
++// 2.12.0.  https://bugs.launchpad.net/qemu/+bug/1701808
++#[cfg_attr(not(any(target_arch = "x86_64", target_arch="i686")), ignore)]
++#[test]
++pub fn test_scm_rights() {
++    use nix::sys::uio::IoVec;
++    use nix::unistd::{pipe, read, write, close};
++    use nix::sys::socket::{socketpair, sendmsg, recvmsg,
++                           AddressFamily, SockType, SockFlag,
++                           ControlMessage, ControlMessageOwned, MsgFlags};
++
++    let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty())
++                     .unwrap();
++    let (r, w) = pipe().unwrap();
++    let mut received_r: Option<RawFd> = None;
++
++    {
++        let iov = [IoVec::from_slice(b"hello")];
++        let fds = [r];
++        let cmsg = ControlMessage::ScmRights(&fds);
++        assert_eq!(sendmsg(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), 5);
++        close(r).unwrap();
++        close(fd1).unwrap();
++    }
++
++    {
++        let mut buf = [0u8; 5];
++        let iov = [IoVec::from_mut_slice(&mut buf[..])];
++        let mut cmsgspace = cmsg_space!([RawFd; 1]);
++        let msg = recvmsg(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap();
++
++        for cmsg in msg.cmsgs() {
++            if let ControlMessageOwned::ScmRights(fd) = cmsg {
++                assert_eq!(received_r, None);
++                assert_eq!(fd.len(), 1);
++                received_r = Some(fd[0]);
++            } else {
++                panic!("unexpected cmsg");
++            }
++        }
++        assert_eq!(msg.bytes, 5);
++        assert!(!msg.flags.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
++        close(fd2).unwrap();
++    }
++
++    let received_r = received_r.expect("Did not receive passed fd");
++    // Ensure that the received file descriptor works
++    write(w, b"world").unwrap();
++    let mut buf = [0u8; 5];
++    read(received_r, &mut buf).unwrap();
++    assert_eq!(&buf[..], b"world");
++    close(received_r).unwrap();
++    close(w).unwrap();
++}
++
++// Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross
++#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "i686")), ignore)]
++#[cfg(any(target_os = "linux", target_os= "android"))]
++#[test]
++pub fn test_af_alg_cipher() {
++    use libc;
++    use nix::sys::uio::IoVec;
++    use nix::unistd::read;
++    use nix::sys::socket::{socket, sendmsg, bind, accept, setsockopt,
++                           AddressFamily, SockType, SockFlag, SockAddr,
++                           ControlMessage, MsgFlags};
++    use nix::sys::socket::sockopt::AlgSetKey;
++
++    let alg_type = "skcipher";
++    let alg_name = "ctr(aes)";
++    // 256-bits secret key
++    let key = vec![0u8; 32];
++    // 16-bytes IV
++    let iv_len = 16;
++    let iv = vec![1u8; iv_len];
++    // 256-bytes plain payload
++    let payload_len = 256;
++    let payload = vec![2u8; payload_len];
++
++    let sock = socket(AddressFamily::Alg, SockType::SeqPacket, SockFlag::empty(), None)
++        .expect("socket failed");
++
++    let sockaddr = SockAddr::new_alg(alg_type, alg_name);
++    bind(sock, &sockaddr).expect("bind failed");
++
++    if let SockAddr::Alg(alg) = sockaddr {
++        assert_eq!(alg.alg_name().to_string_lossy(), alg_name);
++        assert_eq!(alg.alg_type().to_string_lossy(), alg_type);
++    } else {
++        panic!("unexpected SockAddr");
++    }
++
++    setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt");
++    let session_socket = accept(sock).expect("accept failed");
++
++    let msgs = [ControlMessage::AlgSetOp(&libc::ALG_OP_ENCRYPT), ControlMessage::AlgSetIv(iv.as_slice())];
++    let iov = IoVec::from_slice(&payload);
++    sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg encrypt");
++
++    // allocate buffer for encrypted data
++    let mut encrypted = vec![0u8; payload_len];
++    let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt");
++    assert_eq!(num_bytes, payload_len);
++
++    let iov = IoVec::from_slice(&encrypted);
++
++    let iv = vec![1u8; iv_len];
++
++    let msgs = [ControlMessage::AlgSetOp(&libc::ALG_OP_DECRYPT), ControlMessage::AlgSetIv(iv.as_slice())];
++    sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg decrypt");
++
++    // allocate buffer for decrypted data
++    let mut decrypted = vec![0u8; payload_len];
++    let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt");
++
++    assert_eq!(num_bytes, payload_len);
++    assert_eq!(decrypted, payload);
++}
++
++// Disable the test on emulated platforms due to not enabled support of AF_ALG in QEMU from rust cross
++#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "i686")), ignore)]
++#[cfg(any(target_os = "linux", target_os= "android"))]
++#[test]
++pub fn test_af_alg_aead() {
++    use libc::{ALG_OP_DECRYPT, ALG_OP_ENCRYPT};
++    use nix::sys::uio::IoVec;
++    use nix::unistd::{read, close};
++    use nix::sys::socket::{socket, sendmsg, bind, accept, setsockopt,
++                           AddressFamily, SockType, SockFlag, SockAddr,
++                           ControlMessage, MsgFlags};
++    use nix::sys::socket::sockopt::{AlgSetKey, AlgSetAeadAuthSize};
++
++    let auth_size = 4usize;
++    let assoc_size = 16u32;
++
++    let alg_type = "aead";
++    let alg_name = "gcm(aes)";
++    // 256-bits secret key
++    let key = vec![0u8; 32];
++    // 12-bytes IV
++    let iv_len = 12;
++    let iv = vec![1u8; iv_len];
++    // 256-bytes plain payload
++    let payload_len = 256;
++    let mut payload = vec![2u8; payload_len + (assoc_size as usize) + auth_size];
++
++    for i in 0..assoc_size {
++        payload[i as usize] = 10;
++    }
++
++    let len = payload.len();
++
++    for i in 0..auth_size {
++        payload[len - 1 - i] = 0;
++    }
++
++    let sock = socket(AddressFamily::Alg, SockType::SeqPacket, SockFlag::empty(), None)
++        .expect("socket failed");
++
++    let sockaddr = SockAddr::new_alg(alg_type, alg_name);
++    bind(sock, &sockaddr).expect("bind failed");
++
++    setsockopt(sock, AlgSetAeadAuthSize, &auth_size).expect("setsockopt AlgSetAeadAuthSize");
++    setsockopt(sock, AlgSetKey::default(), &key).expect("setsockopt AlgSetKey");
++    let session_socket = accept(sock).expect("accept failed");
++
++    let msgs = [
++        ControlMessage::AlgSetOp(&ALG_OP_ENCRYPT),
++        ControlMessage::AlgSetIv(iv.as_slice()),
++        ControlMessage::AlgSetAeadAssoclen(&assoc_size)];
++    let iov = IoVec::from_slice(&payload);
++    sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg encrypt");
++
++    // allocate buffer for encrypted data
++    let mut encrypted = vec![0u8; (assoc_size as usize) + payload_len + auth_size];
++    let num_bytes = read(session_socket, &mut encrypted).expect("read encrypt");
++    assert_eq!(num_bytes, payload_len + auth_size + (assoc_size as usize));
++    close(session_socket).expect("close");
++
++    for i in 0..assoc_size {
++        encrypted[i as usize] = 10;
++    }
++
++    let iov = IoVec::from_slice(&encrypted);
++
++    let iv = vec![1u8; iv_len];
++
++    let session_socket = accept(sock).expect("accept failed");
++
++    let msgs = [
++        ControlMessage::AlgSetOp(&ALG_OP_DECRYPT),
++        ControlMessage::AlgSetIv(iv.as_slice()),
++        ControlMessage::AlgSetAeadAssoclen(&assoc_size),
++    ];
++    sendmsg(session_socket, &[iov], &msgs, MsgFlags::empty(), None).expect("sendmsg decrypt");
++
++    // allocate buffer for decrypted data
++    let mut decrypted = vec![0u8; payload_len + (assoc_size as usize) + auth_size];
++    let num_bytes = read(session_socket, &mut decrypted).expect("read decrypt");
++
++    assert!(num_bytes >= payload_len + (assoc_size as usize));
++    assert_eq!(decrypted[(assoc_size as usize)..(payload_len + (assoc_size as usize))], payload[(assoc_size as usize)..payload_len + (assoc_size as usize)]);
++}
++
++/// Tests that passing multiple fds using a single `ControlMessage` works.
++// Disable the test on emulated platforms due to a bug in QEMU versions <
++// 2.12.0.  https://bugs.launchpad.net/qemu/+bug/1701808
++#[cfg_attr(not(any(target_arch = "x86_64", target_arch="i686")), ignore)]
++#[test]
++fn test_scm_rights_single_cmsg_multiple_fds() {
++    use std::os::unix::net::UnixDatagram;
++    use std::os::unix::io::{RawFd, AsRawFd};
++    use std::thread;
++    use nix::sys::socket::{ControlMessage, ControlMessageOwned, MsgFlags,
++        sendmsg, recvmsg};
++    use nix::sys::uio::IoVec;
++    use libc;
++
++    let (send, receive) = UnixDatagram::pair().unwrap();
++    let thread = thread::spawn(move || {
++        let mut buf = [0u8; 8];
++        let iovec = [IoVec::from_mut_slice(&mut buf)];
++        let mut space = cmsg_space!([RawFd; 2]);
++        let msg = recvmsg(
++            receive.as_raw_fd(),
++            &iovec,
++            Some(&mut space),
++            MsgFlags::empty()
++        ).unwrap();
++        assert!(!msg.flags.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
++
++        let mut cmsgs = msg.cmsgs();
++        match cmsgs.next() {
++            Some(ControlMessageOwned::ScmRights(fds)) => {
++                assert_eq!(fds.len(), 2,
++                           "unexpected fd count (expected 2 fds, got {})",
++                           fds.len());
++            },
++            _ => panic!(),
++        }
++        assert!(cmsgs.next().is_none(), "unexpected control msg");
++
++        assert_eq!(msg.bytes, 8);
++        assert_eq!(iovec[0].as_slice(), [1u8, 2, 3, 4, 5, 6, 7, 8]);
++    });
++
++    let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
++    let iov = [IoVec::from_slice(&slice)];
++    let fds = [libc::STDIN_FILENO, libc::STDOUT_FILENO];    // pass stdin and stdout
++    let cmsg = [ControlMessage::ScmRights(&fds)];
++    sendmsg(send.as_raw_fd(), &iov, &cmsg, MsgFlags::empty(), None).unwrap();
++    thread.join().unwrap();
++}
++
++// Verify `sendmsg` builds a valid `msghdr` when passing an empty
++// `cmsgs` argument.  This should result in a msghdr with a nullptr
++// msg_control field and a msg_controllen of 0 when calling into the
++// raw `sendmsg`.
++#[test]
++pub fn test_sendmsg_empty_cmsgs() {
++    use nix::sys::uio::IoVec;
++    use nix::unistd::close;
++    use nix::sys::socket::{socketpair, sendmsg, recvmsg,
++                           AddressFamily, SockType, SockFlag, MsgFlags};
++
++    let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty())
++                     .unwrap();
++
++    {
++        let iov = [IoVec::from_slice(b"hello")];
++        assert_eq!(sendmsg(fd1, &iov, &[], MsgFlags::empty(), None).unwrap(), 5);
++        close(fd1).unwrap();
++    }
++
++    {
++        let mut buf = [0u8; 5];
++        let iov = [IoVec::from_mut_slice(&mut buf[..])];
++        let mut cmsgspace = cmsg_space!([RawFd; 1]);
++        let msg = recvmsg(fd2, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap();
++
++        for _ in msg.cmsgs() {
++            panic!("unexpected cmsg");
++        }
++        assert!(!msg.flags.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
++        assert_eq!(msg.bytes, 5);
++        close(fd2).unwrap();
++    }
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++#[test]
++fn test_scm_credentials() {
++    use libc;
++    use nix::sys::uio::IoVec;
++    use nix::unistd::{close, getpid, getuid, getgid};
++    use nix::sys::socket::{socketpair, sendmsg, recvmsg, setsockopt,
++                           AddressFamily, SockType, SockFlag,
++                           ControlMessage, ControlMessageOwned, MsgFlags};
++    use nix::sys::socket::sockopt::PassCred;
++
++    let (send, recv) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty())
++        .unwrap();
++    setsockopt(recv, PassCred, &true).unwrap();
++
++    {
++        let iov = [IoVec::from_slice(b"hello")];
++        let cred = libc::ucred {
++            pid: getpid().as_raw(),
++            uid: getuid().as_raw(),
++            gid: getgid().as_raw(),
++        };
++        let cmsg = ControlMessage::ScmCredentials(&cred);
++        assert_eq!(sendmsg(send, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), 5);
++        close(send).unwrap();
++    }
++
++    {
++        let mut buf = [0u8; 5];
++        let iov = [IoVec::from_mut_slice(&mut buf[..])];
++        let mut cmsgspace = cmsg_space!(libc::ucred);
++        let msg = recvmsg(recv, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap();
++        let mut received_cred = None;
++
++        for cmsg in msg.cmsgs() {
++            if let ControlMessageOwned::ScmCredentials(cred) = cmsg {
++                assert!(received_cred.is_none());
++                assert_eq!(cred.pid, getpid().as_raw());
++                assert_eq!(cred.uid, getuid().as_raw());
++                assert_eq!(cred.gid, getgid().as_raw());
++                received_cred = Some(cred);
++            } else {
++                panic!("unexpected cmsg");
++            }
++        }
++        received_cred.expect("no creds received");
++        assert_eq!(msg.bytes, 5);
++        assert!(!msg.flags.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
++        close(recv).unwrap();
++    }
++}
++
++/// Ensure that we can send `SCM_CREDENTIALS` and `SCM_RIGHTS` with a single
++/// `sendmsg` call.
++#[cfg(any(target_os = "android", target_os = "linux"))]
++// qemu's handling of multiple cmsgs is bugged, ignore tests on non-x86
++// see https://bugs.launchpad.net/qemu/+bug/1781280
++#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "x86")), ignore)]
++#[test]
++fn test_scm_credentials_and_rights() {
++    use libc;
++
++    let space = cmsg_space!(libc::ucred, RawFd);
++    test_impl_scm_credentials_and_rights(space);
++}
++
++/// Ensure that passing a an oversized control message buffer to recvmsg
++/// still works.
++#[cfg(any(target_os = "android", target_os = "linux"))]
++// qemu's handling of multiple cmsgs is bugged, ignore tests on non-x86
++// see https://bugs.launchpad.net/qemu/+bug/1781280
++#[cfg_attr(not(any(target_arch = "x86_64", target_arch = "x86")), ignore)]
++#[test]
++fn test_too_large_cmsgspace() {
++    let space = vec![0u8; 1024];
++    test_impl_scm_credentials_and_rights(space);
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++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::sys::socket::{socketpair, sendmsg, recvmsg, setsockopt,
++                           SockType, SockFlag,
++                           ControlMessage, ControlMessageOwned, MsgFlags};
++    use nix::sys::socket::sockopt::PassCred;
++
++    let (send, recv) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty())
++        .unwrap();
++    setsockopt(recv, PassCred, &true).unwrap();
++
++    let (r, w) = pipe().unwrap();
++    let mut received_r: Option<RawFd> = None;
++
++    {
++        let iov = [IoVec::from_slice(b"hello")];
++        let cred = ucred {
++            pid: getpid().as_raw(),
++            uid: getuid().as_raw(),
++            gid: getgid().as_raw(),
++        };
++        let fds = [r];
++        let cmsgs = [
++            ControlMessage::ScmCredentials(&cred),
++            ControlMessage::ScmRights(&fds),
++        ];
++        assert_eq!(sendmsg(send, &iov, &cmsgs, MsgFlags::empty(), None).unwrap(), 5);
++        close(r).unwrap();
++        close(send).unwrap();
++    }
++
++    {
++        let mut buf = [0u8; 5];
++        let iov = [IoVec::from_mut_slice(&mut buf[..])];
++        let msg = recvmsg(recv, &iov, Some(&mut space), MsgFlags::empty()).unwrap();
++        let mut received_cred = None;
++
++        assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs");
++
++        for cmsg in msg.cmsgs() {
++            match cmsg {
++                ControlMessageOwned::ScmRights(fds) => {
++                    assert_eq!(received_r, None, "already received fd");
++                    assert_eq!(fds.len(), 1);
++                    received_r = Some(fds[0]);
++                }
++                ControlMessageOwned::ScmCredentials(cred) => {
++                    assert!(received_cred.is_none());
++                    assert_eq!(cred.pid, getpid().as_raw());
++                    assert_eq!(cred.uid, getuid().as_raw());
++                    assert_eq!(cred.gid, getgid().as_raw());
++                    received_cred = Some(cred);
++                }
++                _ => panic!("unexpected cmsg"),
++            }
++        }
++        received_cred.expect("no creds received");
++        assert_eq!(msg.bytes, 5);
++        assert!(!msg.flags.intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC));
++        close(recv).unwrap();
++    }
++
++    let received_r = received_r.expect("Did not receive passed fd");
++    // Ensure that the received file descriptor works
++    write(w, b"world").unwrap();
++    let mut buf = [0u8; 5];
++    read(received_r, &mut buf).unwrap();
++    assert_eq!(&buf[..], b"world");
++    close(received_r).unwrap();
++    close(w).unwrap();
++}
++
++// Test creating and using named unix domain sockets
++#[test]
++pub fn test_unixdomain() {
++    use nix::sys::socket::{SockType, SockFlag};
++    use nix::sys::socket::{bind, socket, connect, listen, accept, SockAddr};
++    use nix::unistd::{read, write, close};
++    use std::thread;
++
++    let tempdir = tempfile::tempdir().unwrap();
++    let sockname = tempdir.path().join("sock");
++    let s1 = socket(AddressFamily::Unix, SockType::Stream,
++                    SockFlag::empty(), None).expect("socket failed");
++    let sockaddr = SockAddr::new_unix(&sockname).unwrap();
++    bind(s1, &sockaddr).expect("bind failed");
++    listen(s1, 10).expect("listen failed");
++
++    let thr = thread::spawn(move || {
++        let s2 = socket(AddressFamily::Unix, SockType::Stream, SockFlag::empty(), None)
++                 .expect("socket failed");
++        connect(s2, &sockaddr).expect("connect failed");
++        write(s2, b"hello").expect("write failed");
++        close(s2).unwrap();
++    });
++
++    let s3 = accept(s1).expect("accept failed");
++
++    let mut buf = [0;5];
++    read(s3, &mut buf).unwrap();
++    close(s3).unwrap();
++    close(s1).unwrap();
++    thr.join().unwrap();
++
++    assert_eq!(&buf[..], b"hello");
++}
++
++// Test creating and using named system control sockets
++#[cfg(any(target_os = "macos", target_os = "ios"))]
++#[test]
++pub fn test_syscontrol() {
++    use nix::Error;
++    use nix::errno::Errno;
++    use nix::sys::socket::{socket, SockAddr, SockType, SockFlag, SockProtocol};
++
++    let fd = socket(AddressFamily::System, SockType::Datagram,
++                    SockFlag::empty(), SockProtocol::KextControl)
++             .expect("socket failed");
++    let _sockaddr = SockAddr::new_sys_control(fd, "com.apple.net.utun_control", 0).expect("resolving sys_control name failed");
++    assert_eq!(SockAddr::new_sys_control(fd, "foo.bar.lol", 0).err(), Some(Error::Sys(Errno::ENOENT)));
++
++    // requires root privileges
++    // connect(fd, &sockaddr).expect("connect failed");
++}
++
++#[cfg(any(
++    target_os = "android",
++    target_os = "freebsd",
++    target_os = "ios",
++    target_os = "linux",
++    target_os = "macos",
++    target_os = "netbsd",
++    target_os = "openbsd",
++))]
++fn loopback_address(family: AddressFamily) -> Option<InterfaceAddress> {
++    use std::io;
++    use std::io::Write;
++    use nix::ifaddrs::getifaddrs;
++    use nix::sys::socket::SockAddr;
++    use nix::net::if_::*;
++
++    let addrs = match getifaddrs() {
++        Ok(iter) => iter,
++        Err(e) => {
++            let stdioerr = io::stderr();
++            let mut handle = stdioerr.lock();
++            writeln!(handle, "getifaddrs: {:?}", e).unwrap();
++            return None;
++        },
++    };
++    // return first address matching family
++    for ifaddr in addrs {
++        if ifaddr.flags.contains(InterfaceFlags::IFF_LOOPBACK) {
++            match ifaddr.address {
++                Some(SockAddr::Inet(InetAddr::V4(..))) => {
++                    match family {
++                        AddressFamily::Inet => return Some(ifaddr),
++                        _ => continue
++                    }
++                },
++                Some(SockAddr::Inet(InetAddr::V6(..))) => {
++                    match family {
++                        AddressFamily::Inet6 => return Some(ifaddr),
++                        _ => continue
++                    }
++                },
++                _ => continue,
++            }
++        }
++    }
++    None
++}
++
++#[cfg(any(
++    target_os = "android",
++    target_os = "ios",
++    target_os = "linux",
++    target_os = "macos",
++    target_os = "netbsd",
++))]
++// qemu doesn't seem to be emulating this correctly in these architectures
++#[cfg_attr(any(
++    target_arch = "mips",
++    target_arch = "mips64",
++    target_arch = "powerpc64",
++), ignore)]
++#[test]
++pub fn test_recv_ipv4pktinfo() {
++    use libc;
++    use nix::sys::socket::sockopt::Ipv4PacketInfo;
++    use nix::sys::socket::{bind, SockFlag, SockType};
++    use nix::sys::socket::{getsockname, setsockopt, socket};
++    use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags};
++    use nix::sys::uio::IoVec;
++    use nix::net::if_::*;
++
++    let lo_ifaddr = loopback_address(AddressFamily::Inet);
++    let (lo_name, lo) = match lo_ifaddr {
++        Some(ifaddr) => (ifaddr.interface_name,
++                         ifaddr.address.expect("Expect IPv4 address on interface")),
++        None => return,
++    };
++    let receive = socket(
++            AddressFamily::Inet,
++            SockType::Datagram,
++            SockFlag::empty(),
++            None,
++        ).expect("receive socket failed");
++    bind(receive, &lo).expect("bind failed");
++    let sa = getsockname(receive).expect("getsockname failed");
++    setsockopt(receive, Ipv4PacketInfo, &true).expect("setsockopt failed");
++
++    {
++        let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
++        let iov = [IoVec::from_slice(&slice)];
++
++        let send = socket(
++            AddressFamily::Inet,
++            SockType::Datagram,
++            SockFlag::empty(),
++            None,
++        ).expect("send socket failed");
++        sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)).expect("sendmsg failed");
++    }
++
++    {
++        let mut buf = [0u8; 8];
++        let iovec = [IoVec::from_mut_slice(&mut buf)];
++        let mut space = cmsg_space!(libc::in_pktinfo);
++        let msg = recvmsg(
++            receive,
++            &iovec,
++            Some(&mut space),
++            MsgFlags::empty(),
++        ).expect("recvmsg failed");
++        assert!(
++            !msg.flags
++                .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)
++        );
++
++        let mut cmsgs = msg.cmsgs();
++        match cmsgs.next() {
++            Some(ControlMessageOwned::Ipv4PacketInfo(pktinfo)) => {
++                let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex");
++                assert_eq!(
++                    pktinfo.ipi_ifindex as libc::c_uint,
++                    i,
++                    "unexpected ifindex (expected {}, got {})",
++                    i,
++                    pktinfo.ipi_ifindex
++                );
++            }
++            _ => (),
++        }
++        assert!(cmsgs.next().is_none(), "unexpected additional control msg");
++        assert_eq!(msg.bytes, 8);
++        assert_eq!(
++            iovec[0].as_slice(),
++            [1u8, 2, 3, 4, 5, 6, 7, 8]
++        );
++    }
++}
++
++#[cfg(any(
++    target_os = "freebsd",
++    target_os = "ios",
++    target_os = "macos",
++    target_os = "netbsd",
++    target_os = "openbsd",
++))]
++// qemu doesn't seem to be emulating this correctly in these architectures
++#[cfg_attr(any(
++    target_arch = "mips",
++    target_arch = "mips64",
++    target_arch = "powerpc64",
++), ignore)]
++#[test]
++pub fn test_recvif() {
++    use libc;
++    use nix::net::if_::*;
++    use nix::sys::socket::sockopt::{Ipv4RecvIf, Ipv4RecvDstAddr};
++    use nix::sys::socket::{bind, SockFlag, SockType};
++    use nix::sys::socket::{getsockname, setsockopt, socket, SockAddr};
++    use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags};
++    use nix::sys::uio::IoVec;
++
++    let lo_ifaddr = loopback_address(AddressFamily::Inet);
++    let (lo_name, lo) = match lo_ifaddr {
++        Some(ifaddr) => (ifaddr.interface_name,
++                         ifaddr.address.expect("Expect IPv4 address on interface")),
++        None => return,
++    };
++    let receive = socket(
++        AddressFamily::Inet,
++        SockType::Datagram,
++        SockFlag::empty(),
++        None,
++    ).expect("receive socket failed");
++    bind(receive, &lo).expect("bind failed");
++    let sa = getsockname(receive).expect("getsockname failed");
++    setsockopt(receive, Ipv4RecvIf, &true).expect("setsockopt IP_RECVIF failed");
++    setsockopt(receive, Ipv4RecvDstAddr, &true).expect("setsockopt IP_RECVDSTADDR failed");
++
++    {
++        let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
++        let iov = [IoVec::from_slice(&slice)];
++
++        let send = socket(
++            AddressFamily::Inet,
++            SockType::Datagram,
++            SockFlag::empty(),
++            None,
++        ).expect("send socket failed");
++        sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)).expect("sendmsg failed");
++    }
++
++    {
++        let mut buf = [0u8; 8];
++        let iovec = [IoVec::from_mut_slice(&mut buf)];
++        let mut space = cmsg_space!(libc::sockaddr_dl, libc::in_addr);
++        let msg = recvmsg(
++            receive,
++            &iovec,
++            Some(&mut space),
++            MsgFlags::empty(),
++        ).expect("recvmsg failed");
++        assert!(
++            !msg.flags
++                .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)
++        );
++        assert_eq!(msg.cmsgs().count(), 2, "expected 2 cmsgs");
++
++        let mut rx_recvif = false;
++        let mut rx_recvdstaddr = false;
++        for cmsg in msg.cmsgs() {
++            match cmsg {
++                ControlMessageOwned::Ipv4RecvIf(dl) => {
++                    rx_recvif = true;
++                    let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex");
++                    assert_eq!(
++                        dl.sdl_index as libc::c_uint,
++                        i,
++                        "unexpected ifindex (expected {}, got {})",
++                        i,
++                        dl.sdl_index
++                    );
++                },
++                ControlMessageOwned::Ipv4RecvDstAddr(addr) => {
++                    rx_recvdstaddr = true;
++                    if let SockAddr::Inet(InetAddr::V4(a)) = lo {
++                        assert_eq!(a.sin_addr.s_addr,
++                                   addr.s_addr,
++                                   "unexpected destination address (expected {}, got {})",
++                                   a.sin_addr.s_addr,
++                                   addr.s_addr);
++                    } else {
++                        panic!("unexpected Sockaddr");
++                    }
++                },
++                _ => panic!("unexpected additional control msg"),
++            }
++        }
++        assert_eq!(rx_recvif, true);
++        assert_eq!(rx_recvdstaddr, true);
++        assert_eq!(msg.bytes, 8);
++        assert_eq!(
++            iovec[0].as_slice(),
++            [1u8, 2, 3, 4, 5, 6, 7, 8]
++        );
++    }
++}
++
++#[cfg(any(
++    target_os = "android",
++    target_os = "freebsd",
++    target_os = "ios",
++    target_os = "linux",
++    target_os = "macos",
++    target_os = "netbsd",
++    target_os = "openbsd",
++))]
++// qemu doesn't seem to be emulating this correctly in these architectures
++#[cfg_attr(any(
++    target_arch = "mips",
++    target_arch = "mips64",
++    target_arch = "powerpc64",
++), ignore)]
++#[test]
++pub fn test_recv_ipv6pktinfo() {
++    use libc;
++    use nix::net::if_::*;
++    use nix::sys::socket::sockopt::Ipv6RecvPacketInfo;
++    use nix::sys::socket::{bind, SockFlag, SockType};
++    use nix::sys::socket::{getsockname, setsockopt, socket};
++    use nix::sys::socket::{recvmsg, sendmsg, ControlMessageOwned, MsgFlags};
++    use nix::sys::uio::IoVec;
++
++    let lo_ifaddr = loopback_address(AddressFamily::Inet6);
++    let (lo_name, lo) = match lo_ifaddr {
++        Some(ifaddr) => (ifaddr.interface_name,
++                         ifaddr.address.expect("Expect IPv4 address on interface")),
++        None => return,
++    };
++    let receive = socket(
++        AddressFamily::Inet6,
++        SockType::Datagram,
++        SockFlag::empty(),
++        None,
++    ).expect("receive socket failed");
++    bind(receive, &lo).expect("bind failed");
++    let sa = getsockname(receive).expect("getsockname failed");
++    setsockopt(receive, Ipv6RecvPacketInfo, &true).expect("setsockopt failed");
++
++    {
++        let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
++        let iov = [IoVec::from_slice(&slice)];
++
++        let send = socket(
++            AddressFamily::Inet6,
++            SockType::Datagram,
++            SockFlag::empty(),
++            None,
++        ).expect("send socket failed");
++        sendmsg(send, &iov, &[], MsgFlags::empty(), Some(&sa)).expect("sendmsg failed");
++    }
++
++    {
++        let mut buf = [0u8; 8];
++        let iovec = [IoVec::from_mut_slice(&mut buf)];
++        let mut space = cmsg_space!(libc::in6_pktinfo);
++        let msg = recvmsg(
++            receive,
++            &iovec,
++            Some(&mut space),
++            MsgFlags::empty(),
++        ).expect("recvmsg failed");
++        assert!(
++            !msg.flags
++                .intersects(MsgFlags::MSG_TRUNC | MsgFlags::MSG_CTRUNC)
++        );
++
++        let mut cmsgs = msg.cmsgs();
++        match cmsgs.next() {
++            Some(ControlMessageOwned::Ipv6PacketInfo(pktinfo)) => {
++                let i = if_nametoindex(lo_name.as_bytes()).expect("if_nametoindex");
++                assert_eq!(
++                    pktinfo.ipi6_ifindex,
++                    i,
++                    "unexpected ifindex (expected {}, got {})",
++                    i,
++                    pktinfo.ipi6_ifindex
++                );
++            }
++            _ => (),
++        }
++        assert!(cmsgs.next().is_none(), "unexpected additional control msg");
++        assert_eq!(msg.bytes, 8);
++        assert_eq!(
++            iovec[0].as_slice(),
++            [1u8, 2, 3, 4, 5, 6, 7, 8]
++        );
++    }
++}
++
++#[cfg(target_os = "linux")]
++#[test]
++pub fn test_vsock() {
++    use libc;
++    use nix::Error;
++    use nix::errno::Errno;
++    use nix::sys::socket::{AddressFamily, socket, bind, connect, listen,
++                           SockAddr, SockType, SockFlag};
++    use nix::unistd::{close};
++    use std::thread;
++
++    let port: u32 = 3000;
++
++    let s1 = socket(AddressFamily::Vsock,  SockType::Stream,
++                    SockFlag::empty(), None)
++             .expect("socket failed");
++
++    // VMADDR_CID_HYPERVISOR and VMADDR_CID_RESERVED are reserved, so we expect
++    // an EADDRNOTAVAIL error.
++    let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_HYPERVISOR, port);
++    assert_eq!(bind(s1, &sockaddr).err(),
++               Some(Error::Sys(Errno::EADDRNOTAVAIL)));
++
++    let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_RESERVED, port);
++    assert_eq!(bind(s1, &sockaddr).err(),
++               Some(Error::Sys(Errno::EADDRNOTAVAIL)));
++
++
++    let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_ANY, port);
++    assert_eq!(bind(s1, &sockaddr), Ok(()));
++    listen(s1, 10).expect("listen failed");
++
++    let thr = thread::spawn(move || {
++        let cid: u32 = libc::VMADDR_CID_HOST;
++
++        let s2 = socket(AddressFamily::Vsock, SockType::Stream,
++                        SockFlag::empty(), None)
++                 .expect("socket failed");
++
++        let sockaddr = SockAddr::new_vsock(cid, port);
++
++        // The current implementation does not support loopback devices, so,
++        // for now, we expect a failure on the connect.
++        assert_ne!(connect(s2, &sockaddr), Ok(()));
++
++        close(s2).unwrap();
++    });
++
++    close(s1).unwrap();
++    thr.join().unwrap();
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_sockopt.rs b/third_party/rust/nix-0.15.0/test/sys/test_sockopt.rs
+new file mode 100644
+index 0000000000000..c4860c0d61d3d
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_sockopt.rs
+@@ -0,0 +1,53 @@
++use rand::{thread_rng, Rng};
++use nix::sys::socket::{socket, sockopt, getsockopt, setsockopt, AddressFamily, SockType, SockFlag, SockProtocol};
++
++#[cfg(target_os = "linux")]
++#[test]
++fn is_so_mark_functional() {
++    use nix::sys::socket::sockopt;
++
++    require_capability!(CAP_NET_ADMIN);
++
++    let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
++    setsockopt(s, sockopt::Mark, &1337).unwrap();
++    let mark = getsockopt(s, sockopt::Mark).unwrap();
++    assert_eq!(mark, 1337);
++}
++
++#[test]
++fn test_so_buf() {
++    let fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), SockProtocol::Udp)
++             .unwrap();
++    let bufsize: usize = thread_rng().gen_range(4096, 131_072);
++    setsockopt(fd, sockopt::SndBuf, &bufsize).unwrap();
++    let actual = getsockopt(fd, sockopt::SndBuf).unwrap();
++    assert!(actual >= bufsize);
++    setsockopt(fd, sockopt::RcvBuf, &bufsize).unwrap();
++    let actual = getsockopt(fd, sockopt::RcvBuf).unwrap();
++    assert!(actual >= bufsize);
++}
++
++// The CI doesn't supported getsockopt and setsockopt on emulated processors.
++// It's beleived that a QEMU issue, the tests run ok on a fully emulated system.
++// Current CI just run the binary with QEMU but the Kernel remains the same as the host.
++// So the syscall doesn't work properly unless the kernel is also emulated.
++#[test]
++#[cfg(all(
++    any(target_arch = "x86", target_arch = "x86_64"),
++    any(target_os = "freebsd", target_os = "linux")
++))]
++fn test_tcp_congestion() {
++    use std::ffi::OsString;
++
++    let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
++
++    let val = getsockopt(fd, sockopt::TcpCongestion).unwrap();
++    setsockopt(fd, sockopt::TcpCongestion, &val).unwrap();
++
++    setsockopt(fd, sockopt::TcpCongestion, &OsString::from("tcp_congestion_does_not_exist")).unwrap_err();
++
++    assert_eq!(
++        getsockopt(fd, sockopt::TcpCongestion).unwrap(),
++        val
++    );
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_sysinfo.rs b/third_party/rust/nix-0.15.0/test/sys/test_sysinfo.rs
+new file mode 100644
+index 0000000000000..73e6586f6223e
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_sysinfo.rs
+@@ -0,0 +1,18 @@
++use nix::sys::sysinfo::*;
++
++#[test]
++fn sysinfo_works() {
++    let info = sysinfo().unwrap();
++
++    let (l1, l5, l15) = info.load_average();
++    assert!(l1 >= 0.0);
++    assert!(l5 >= 0.0);
++    assert!(l15 >= 0.0);
++
++    info.uptime();  // just test Duration construction
++
++    assert!(info.swap_free() <= info.swap_total(),
++            "more swap available than installed (free: {}, total: {})",
++            info.swap_free(),
++            info.swap_total());
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_termios.rs b/third_party/rust/nix-0.15.0/test/sys/test_termios.rs
+new file mode 100644
+index 0000000000000..a14b8ce1a23cb
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_termios.rs
+@@ -0,0 +1,136 @@
++use std::os::unix::prelude::*;
++use tempfile::tempfile;
++
++use nix::{Error, fcntl};
++use nix::errno::Errno;
++use nix::pty::openpty;
++use nix::sys::termios::{self, LocalFlags, OutputFlags, Termios, tcgetattr};
++use nix::unistd::{read, write, close};
++
++/// Helper function analogous to `std::io::Write::write_all`, but for `RawFd`s
++fn write_all(f: RawFd, buf: &[u8]) {
++    let mut len = 0;
++    while len < buf.len() {
++        len += write(f, &buf[len..]).unwrap();
++    }
++}
++
++// Test tcgetattr on a terminal
++#[test]
++fn test_tcgetattr_pty() {
++    // openpty uses ptname(3) internally
++    let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++
++    let pty = openpty(None, None).expect("openpty failed");
++    assert!(termios::tcgetattr(pty.master).is_ok());
++    close(pty.master).expect("closing the master failed");
++    close(pty.slave).expect("closing the slave failed");
++}
++
++// Test tcgetattr on something that isn't a terminal
++#[test]
++fn test_tcgetattr_enotty() {
++    let file = tempfile().unwrap();
++    assert_eq!(termios::tcgetattr(file.as_raw_fd()).err(),
++               Some(Error::Sys(Errno::ENOTTY)));
++}
++
++// Test tcgetattr on an invalid file descriptor
++#[test]
++fn test_tcgetattr_ebadf() {
++    assert_eq!(termios::tcgetattr(-1).err(),
++               Some(Error::Sys(Errno::EBADF)));
++}
++
++// Test modifying output flags
++#[test]
++fn test_output_flags() {
++    // openpty uses ptname(3) internally
++    let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++
++    // Open one pty to get attributes for the second one
++    let mut termios = {
++        let pty = openpty(None, None).expect("openpty failed");
++        assert!(pty.master > 0);
++        assert!(pty.slave > 0);
++        let termios = tcgetattr(pty.master).expect("tcgetattr failed");
++        close(pty.master).unwrap();
++        close(pty.slave).unwrap();
++        termios
++    };
++
++    // Make sure postprocessing '\r' isn't specified by default or this test is useless.
++    assert!(!termios.output_flags.contains(OutputFlags::OPOST | OutputFlags::OCRNL));
++
++    // Specify that '\r' characters should be transformed to '\n'
++    // OPOST is specified to enable post-processing
++    termios.output_flags.insert(OutputFlags::OPOST | OutputFlags::OCRNL);
++
++    // Open a pty
++    let pty = openpty(None, &termios).unwrap();
++    assert!(pty.master > 0);
++    assert!(pty.slave > 0);
++
++    // Write into the master
++    let string = "foofoofoo\r";
++    write_all(pty.master, string.as_bytes());
++
++    // Read from the slave verifying that the output has been properly transformed
++    let mut buf = [0u8; 10];
++    ::read_exact(pty.slave, &mut buf);
++    let transformed_string = "foofoofoo\n";
++    close(pty.master).unwrap();
++    close(pty.slave).unwrap();
++    assert_eq!(&buf, transformed_string.as_bytes());
++}
++
++// Test modifying local flags
++#[test]
++fn test_local_flags() {
++    // openpty uses ptname(3) internally
++    let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++
++    // Open one pty to get attributes for the second one
++    let mut termios = {
++        let pty = openpty(None, None).unwrap();
++        assert!(pty.master > 0);
++        assert!(pty.slave > 0);
++        let termios = tcgetattr(pty.master).unwrap();
++        close(pty.master).unwrap();
++        close(pty.slave).unwrap();
++        termios
++    };
++
++    // Make sure echo is specified by default or this test is useless.
++    assert!(termios.local_flags.contains(LocalFlags::ECHO));
++
++    // Disable local echo
++    termios.local_flags.remove(LocalFlags::ECHO);
++
++    // Open a new pty with our modified termios settings
++    let pty = openpty(None, &termios).unwrap();
++    assert!(pty.master > 0);
++    assert!(pty.slave > 0);
++
++    // Set the master is in nonblocking mode or reading will never return.
++    let flags = fcntl::fcntl(pty.master, fcntl::F_GETFL).unwrap();
++    let new_flags = fcntl::OFlag::from_bits_truncate(flags) | fcntl::OFlag::O_NONBLOCK;
++    fcntl::fcntl(pty.master, fcntl::F_SETFL(new_flags)).unwrap();
++
++    // Write into the master
++    let string = "foofoofoo\r";
++    write_all(pty.master, string.as_bytes());
++
++    // Try to read from the master, which should not have anything as echoing was disabled.
++    let mut buf = [0u8; 10];
++    let read = read(pty.master, &mut buf).unwrap_err();
++    close(pty.master).unwrap();
++    close(pty.slave).unwrap();
++    assert_eq!(read, Error::Sys(Errno::EAGAIN));
++}
++
++#[test]
++fn test_cfmakeraw() {
++    let mut termios = unsafe { Termios::default_uninit() };
++    termios::cfmakeraw(&mut termios);
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_uio.rs b/third_party/rust/nix-0.15.0/test/sys/test_uio.rs
+new file mode 100644
+index 0000000000000..3e4fc28ceb0e4
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_uio.rs
+@@ -0,0 +1,241 @@
++use nix::sys::uio::*;
++use nix::unistd::*;
++use rand::{thread_rng, Rng};
++use rand::distributions::Alphanumeric;
++use std::{cmp, iter};
++use std::fs::{OpenOptions};
++use std::os::unix::io::AsRawFd;
++
++use tempfile::{tempfile, tempdir};
++
++#[test]
++fn test_writev() {
++    let mut to_write = Vec::with_capacity(16 * 128);
++    for _ in 0..16 {
++        let s: String = thread_rng().sample_iter(&Alphanumeric).take(128).collect();
++        let b = s.as_bytes();
++        to_write.extend(b.iter().cloned());
++    }
++    // Allocate and fill iovecs
++    let mut iovecs = Vec::new();
++    let mut consumed = 0;
++    while consumed < to_write.len() {
++        let left = to_write.len() - consumed;
++        let slice_len = if left <= 64 { left } else { thread_rng().gen_range(64, cmp::min(256, left)) };
++        let b = &to_write[consumed..consumed+slice_len];
++        iovecs.push(IoVec::from_slice(b));
++        consumed += slice_len;
++    }
++    let pipe_res = pipe();
++    assert!(pipe_res.is_ok());
++    let (reader, writer) = pipe_res.ok().unwrap();
++    // FileDesc will close its filedesc (reader).
++    let mut read_buf: Vec<u8> = iter::repeat(0u8).take(128 * 16).collect();
++    // Blocking io, should write all data.
++    let write_res = writev(writer, &iovecs);
++    // Successful write
++    assert!(write_res.is_ok());
++    let written = write_res.ok().unwrap();
++    // Check whether we written all data
++    assert_eq!(to_write.len(), written);
++    let read_res = read(reader, &mut read_buf[..]);
++    // Successful read
++    assert!(read_res.is_ok());
++    let read = read_res.ok().unwrap() as usize;
++    // Check we have read as much as we written
++    assert_eq!(read, written);
++    // Check equality of written and read data
++    assert_eq!(&to_write, &read_buf);
++    let close_res = close(writer);
++    assert!(close_res.is_ok());
++    let close_res = close(reader);
++    assert!(close_res.is_ok());
++}
++
++#[test]
++fn test_readv() {
++    let s:String = thread_rng().sample_iter(&Alphanumeric).take(128).collect();
++    let to_write = s.as_bytes().to_vec();
++    let mut storage = Vec::new();
++    let mut allocated = 0;
++    while allocated < to_write.len() {
++        let left = to_write.len() - allocated;
++        let vec_len = if left <= 64 { left } else { thread_rng().gen_range(64, cmp::min(256, left)) };
++        let v: Vec<u8> = iter::repeat(0u8).take(vec_len).collect();
++        storage.push(v);
++        allocated += vec_len;
++    }
++    let mut iovecs = Vec::with_capacity(storage.len());
++    for v in &mut storage {
++        iovecs.push(IoVec::from_mut_slice(&mut v[..]));
++    }
++    let pipe_res = pipe();
++    assert!(pipe_res.is_ok());
++    let (reader, writer) = pipe_res.ok().unwrap();
++    // Blocking io, should write all data.
++    let write_res = write(writer, &to_write);
++    // Successful write
++    assert!(write_res.is_ok());
++    let read_res = readv(reader, &mut iovecs[..]);
++    assert!(read_res.is_ok());
++    let read = read_res.ok().unwrap();
++    // Check whether we've read all data
++    assert_eq!(to_write.len(), read);
++    // Cccumulate data from iovecs
++    let mut read_buf = Vec::with_capacity(to_write.len());
++    for iovec in &iovecs {
++        read_buf.extend(iovec.as_slice().iter().cloned());
++    }
++    // Check whether iovecs contain all written data
++    assert_eq!(read_buf.len(), to_write.len());
++    // Check equality of written and read data
++    assert_eq!(&read_buf, &to_write);
++    let close_res = close(reader);
++    assert!(close_res.is_ok());
++    let close_res = close(writer);
++    assert!(close_res.is_ok());
++}
++
++#[test]
++fn test_pwrite() {
++    use std::io::Read;
++
++    let mut file = tempfile().unwrap();
++    let buf = [1u8;8];
++    assert_eq!(Ok(8), pwrite(file.as_raw_fd(), &buf, 8));
++    let mut file_content = Vec::new();
++    file.read_to_end(&mut file_content).unwrap();
++    let mut expected = vec![0u8;8];
++    expected.extend(vec![1;8]);
++    assert_eq!(file_content, expected);
++}
++
++#[test]
++fn test_pread() {
++    use std::io::Write;
++
++    let tempdir = tempdir().unwrap();
++
++    let path = tempdir.path().join("pread_test_file");
++    let mut file = OpenOptions::new().write(true).read(true).create(true)
++                                    .truncate(true).open(path).unwrap();
++    let file_content: Vec<u8> = (0..64).collect();
++    file.write_all(&file_content).unwrap();
++
++    let mut buf = [0u8;16];
++    assert_eq!(Ok(16), pread(file.as_raw_fd(), &mut buf, 16));
++    let expected: Vec<_> = (16..32).collect();
++    assert_eq!(&buf[..], &expected[..]);
++}
++
++#[test]
++#[cfg(target_os = "linux")]
++fn test_pwritev() {
++    use std::io::Read;
++
++    let to_write: Vec<u8> = (0..128).collect();
++    let expected: Vec<u8> = [vec![0;100], to_write.clone()].concat();
++
++    let iovecs = [
++        IoVec::from_slice(&to_write[0..17]),
++        IoVec::from_slice(&to_write[17..64]),
++        IoVec::from_slice(&to_write[64..128]),
++    ];
++
++    let tempdir = tempdir().unwrap();
++
++    // pwritev them into a temporary file
++    let path = tempdir.path().join("pwritev_test_file");
++    let mut file = OpenOptions::new().write(true).read(true).create(true)
++                                    .truncate(true).open(path).unwrap();
++
++    let written = pwritev(file.as_raw_fd(), &iovecs, 100).ok().unwrap();
++    assert_eq!(written, to_write.len());
++
++    // Read the data back and make sure it matches
++    let mut contents = Vec::new();
++    file.read_to_end(&mut contents).unwrap();
++    assert_eq!(contents, expected);
++}
++
++#[test]
++#[cfg(target_os = "linux")]
++fn test_preadv() {
++    use std::io::Write;
++
++    let to_write: Vec<u8> = (0..200).collect();
++    let expected: Vec<u8> = (100..200).collect();
++
++    let tempdir = tempdir().unwrap();
++
++    let path = tempdir.path().join("preadv_test_file");
++
++    let mut file = OpenOptions::new().read(true).write(true).create(true)
++                                    .truncate(true).open(path).unwrap();
++    file.write_all(&to_write).unwrap();
++
++    let mut buffers: Vec<Vec<u8>> = vec![
++        vec![0; 24],
++        vec![0; 1],
++        vec![0; 75],
++    ];
++
++    {
++        // Borrow the buffers into IoVecs and preadv into them
++        let iovecs: Vec<_> = buffers.iter_mut().map(
++            |buf| IoVec::from_mut_slice(&mut buf[..])).collect();
++        assert_eq!(Ok(100), preadv(file.as_raw_fd(), &iovecs, 100));
++    }
++
++    let all = buffers.concat();
++    assert_eq!(all, expected);
++}
++
++#[test]
++#[cfg(target_os = "linux")]
++// FIXME: qemu-user doesn't implement process_vm_readv/writev on most arches
++#[cfg_attr(not(any(target_arch = "x86", target_arch = "x86_64")), ignore)]
++fn test_process_vm_readv() {
++    use nix::unistd::ForkResult::*;
++    use nix::sys::signal::*;
++    use nix::sys::wait::*;
++
++    let _ = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++
++    // Pre-allocate memory in the child, since allocation isn't safe
++    // post-fork (~= async-signal-safe)
++    let mut vector = vec![1u8, 2, 3, 4, 5];
++
++    let (r, w) = pipe().unwrap();
++    match fork().expect("Error: Fork Failed") {
++        Parent { child } => {
++            close(w).unwrap();
++            // wait for child
++            read(r, &mut [0u8]).unwrap();
++            close(r).unwrap();
++
++            let ptr = vector.as_ptr() as usize;
++            let remote_iov = RemoteIoVec { base: ptr, len: 5 };
++            let mut buf = vec![0u8; 5];
++
++            let ret = process_vm_readv(child,
++                                       &[IoVec::from_mut_slice(&mut buf)],
++                                       &[remote_iov]);
++
++            kill(child, SIGTERM).unwrap();
++            waitpid(child, None).unwrap();
++
++            assert_eq!(Ok(5), ret);
++            assert_eq!(20u8, buf.iter().sum());
++        },
++        Child => {
++            let _ = close(r);
++            for i in &mut vector {
++                *i += 1;
++            }
++            let _ = write(w, b"\0");
++            let _ = close(w);
++            loop { let _ = pause(); }
++        },
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/test/sys/test_wait.rs b/third_party/rust/nix-0.15.0/test/sys/test_wait.rs
+new file mode 100644
+index 0000000000000..d07d82f0d9075
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/sys/test_wait.rs
+@@ -0,0 +1,104 @@
++use nix::Error;
++use nix::unistd::*;
++use nix::unistd::ForkResult::*;
++use nix::sys::signal::*;
++use nix::sys::wait::*;
++use libc::_exit;
++
++#[test]
++fn test_wait_signal() {
++    let _ = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++
++    // Safe: The child only calls `pause` and/or `_exit`, which are async-signal-safe.
++    match fork().expect("Error: Fork Failed") {
++      Child => {
++          pause();
++          unsafe { _exit(123) }
++      },
++      Parent { child } => {
++          kill(child, Some(SIGKILL)).expect("Error: Kill Failed");
++          assert_eq!(waitpid(child, None), Ok(WaitStatus::Signaled(child, SIGKILL, false)));
++      },
++    }
++}
++
++#[test]
++fn test_wait_exit() {
++    let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++
++    // Safe: Child only calls `_exit`, which is async-signal-safe.
++    match fork().expect("Error: Fork Failed") {
++      Child => unsafe { _exit(12); },
++      Parent { child } => {
++          assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 12)));
++      },
++    }
++}
++
++#[test]
++fn test_waitstatus_from_raw() {
++    let pid = Pid::from_raw(1);
++    assert_eq!(WaitStatus::from_raw(pid, 0x0002), Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false)));
++    assert_eq!(WaitStatus::from_raw(pid, 0x0200), Ok(WaitStatus::Exited(pid, 2)));
++    assert_eq!(WaitStatus::from_raw(pid, 0x7f7f), Err(Error::invalid_argument()));
++}
++
++#[test]
++fn test_waitstatus_pid() {
++    let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++
++    match fork().unwrap() {
++        Child => unsafe { _exit(0) },
++        Parent { child } => {
++            let status = waitpid(child, None).unwrap();
++            assert_eq!(status.pid(), Some(child));
++        }
++    }
++}
++
++#[cfg(any(target_os = "linux", target_os = "android"))]
++// FIXME: qemu-user doesn't implement ptrace on most arches
++#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
++mod ptrace {
++    use nix::sys::ptrace::{self, Options, Event};
++    use nix::sys::signal::*;
++    use nix::sys::wait::*;
++    use nix::unistd::*;
++    use nix::unistd::ForkResult::*;
++    use libc::_exit;
++
++    fn ptrace_child() -> ! {
++        ptrace::traceme().unwrap();
++        // As recommended by ptrace(2), raise SIGTRAP to pause the child
++        // until the parent is ready to continue
++        raise(SIGTRAP).unwrap();
++        unsafe { _exit(0) }
++    }
++
++    fn ptrace_parent(child: Pid) {
++        // Wait for the raised SIGTRAP
++        assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, SIGTRAP)));
++        // We want to test a syscall stop and a PTRACE_EVENT stop
++        assert!(ptrace::setoptions(child, Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT).is_ok());
++
++        // First, stop on the next system call, which will be exit()
++        assert!(ptrace::syscall(child).is_ok());
++        assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
++        // Then get the ptrace event for the process exiting
++        assert!(ptrace::cont(child, None).is_ok());
++        assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceEvent(child, SIGTRAP, Event::PTRACE_EVENT_EXIT as i32)));
++        // Finally get the normal wait() result, now that the process has exited
++        assert!(ptrace::cont(child, None).is_ok());
++        assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 0)));
++    }
++
++    #[test]
++    fn test_wait_ptrace() {
++        let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++
++        match fork().expect("Error: Fork Failed") {
++            Child => ptrace_child(),
++            Parent { child } => ptrace_parent(child),
++        }
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test.rs b/third_party/rust/nix-0.15.0/test/test.rs
+new file mode 100644
+index 0000000000000..6a71d261b5712
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test.rs
+@@ -0,0 +1,149 @@
++// XXX Allow deprecated items until release 0.16.0.  See issue #1096.
++#![allow(deprecated)]
++extern crate bytes;
++#[cfg(any(target_os = "android", target_os = "linux"))]
++extern crate caps;
++#[macro_use]
++extern crate cfg_if;
++#[macro_use]
++extern crate nix;
++#[macro_use]
++extern crate lazy_static;
++extern crate libc;
++extern crate rand;
++#[cfg(target_os = "freebsd")]
++extern crate sysctl;
++extern crate tempfile;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++macro_rules! require_capability {
++    ($capname:ident) => {
++        use ::caps::{Capability, CapSet, has_cap};
++        use ::std::io::{self, Write};
++
++        if !has_cap(None, CapSet::Effective, Capability::$capname).unwrap() {
++            let stderr = io::stderr();
++            let mut handle = stderr.lock();
++            writeln!(handle, "Insufficient capabilities. Skipping test.")
++                .unwrap();
++            return;
++        }
++    }
++}
++
++#[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()
++        {
++            use ::std::io::Write;
++            let stderr = ::std::io::stderr();
++            let mut handle = stderr.lock();
++            writeln!(handle, "{} cannot run in a jail. Skipping test.", $name)
++                .unwrap();
++            return;
++        }
++    }
++}
++
++macro_rules! skip_if_not_root {
++    ($name:expr) => {
++        use nix::unistd::Uid;
++
++        if !Uid::current().is_root() {
++            use ::std::io::Write;
++            let stderr = ::std::io::stderr();
++            let mut handle = stderr.lock();
++            writeln!(handle, "{} requires root privileges. Skipping test.", $name).unwrap();
++            return;
++        }
++    };
++}
++
++mod sys;
++mod test_dir;
++mod test_fcntl;
++#[cfg(any(target_os = "android",
++          target_os = "linux"))]
++mod test_kmod;
++#[cfg(any(target_os = "dragonfly",
++          target_os = "freebsd",
++          target_os = "fushsia",
++          target_os = "linux",
++          target_os = "netbsd"))]
++mod test_mq;
++mod test_net;
++mod test_nix_path;
++mod test_poll;
++mod test_pty;
++#[cfg(any(target_os = "android",
++          target_os = "freebsd",
++          target_os = "ios",
++          target_os = "linux",
++          target_os = "macos"))]
++mod test_sendfile;
++mod test_stat;
++mod test_unistd;
++
++use std::os::unix::io::RawFd;
++use std::path::PathBuf;
++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;
++    while len < buf.len() {
++        // get_mut would be better than split_at_mut, but it requires nightly
++        let (_, remaining) = buf.split_at_mut(len);
++        len += read(f, remaining).unwrap();
++    }
++}
++
++lazy_static! {
++    /// Any test that changes the process's current working directory must grab
++    /// the RwLock exclusively.  Any process that cares about the current
++    /// working directory must grab it shared.
++    pub static ref CWD_LOCK: RwLock<()> = RwLock::new(());
++    /// Any test that creates child processes must grab this mutex, regardless
++    /// of what it does with those children.
++    pub static ref FORK_MTX: Mutex<()> = Mutex::new(());
++    /// Any test that changes the process's supplementary groups must grab this
++    /// mutex
++    pub static ref GROUPS_MTX: Mutex<()> = Mutex::new(());
++    /// Any tests that loads or unloads kernel modules must grab this mutex
++    pub static ref KMOD_MTX: Mutex<()> = Mutex::new(());
++    /// Any test that calls ptsname(3) must grab this mutex.
++    pub static ref PTSNAME_MTX: Mutex<()> = Mutex::new(());
++    /// Any test that alters signal handling must grab this mutex.
++    pub static ref SIGNAL_MTX: Mutex<()> = Mutex::new(());
++}
++
++/// RAII object that restores a test's original directory on drop
++struct DirRestore<'a> {
++    d: PathBuf,
++    _g: RwLockWriteGuard<'a, ()>
++}
++
++impl<'a> DirRestore<'a> {
++    fn new() -> Self {
++        let guard = ::CWD_LOCK.write()
++            .expect("Lock got poisoned by another test");
++        DirRestore{
++            _g: guard,
++            d: getcwd().unwrap(),
++        }
++    }
++}
++
++impl<'a> Drop for DirRestore<'a> {
++    fn drop(&mut self) {
++        let r = chdir(&self.d);
++        if std::thread::panicking() {
++            r.unwrap();
++        }
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test_dir.rs b/third_party/rust/nix-0.15.0/test/test_dir.rs
+new file mode 100644
+index 0000000000000..c42fbcd18a29d
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_dir.rs
+@@ -0,0 +1,46 @@
++extern crate nix;
++extern crate tempfile;
++
++use nix::dir::{Dir, Type};
++use nix::fcntl::OFlag;
++use nix::sys::stat::Mode;
++use std::fs::File;
++use self::tempfile::tempdir;
++
++#[test]
++fn read() {
++    let tmp = tempdir().unwrap();
++    File::create(&tmp.path().join("foo")).unwrap();
++    ::std::os::unix::fs::symlink("foo", tmp.path().join("bar")).unwrap();
++    let mut dir = Dir::open(tmp.path(), OFlag::O_DIRECTORY | OFlag::O_RDONLY | OFlag::O_CLOEXEC,
++                            Mode::empty()).unwrap();
++    let mut entries: Vec<_> = dir.iter().map(|e| e.unwrap()).collect();
++    entries.sort_by(|a, b| a.file_name().cmp(b.file_name()));
++    let entry_names: Vec<_> = entries
++        .iter()
++        .map(|e| e.file_name().to_str().unwrap().to_owned())
++        .collect();
++    assert_eq!(&entry_names[..], &[".", "..", "bar", "foo"]);
++
++    // Check file types. The system is allowed to return DT_UNKNOWN (aka None here) but if it does
++    // return a type, ensure it's correct.
++    assert!(&[Some(Type::Directory), None].contains(&entries[0].file_type())); // .: dir
++    assert!(&[Some(Type::Directory), None].contains(&entries[1].file_type())); // ..: dir
++    assert!(&[Some(Type::Symlink), None].contains(&entries[2].file_type())); // bar: symlink
++    assert!(&[Some(Type::File), None].contains(&entries[3].file_type())); // foo: regular file
++}
++
++#[test]
++fn rewind() {
++    let tmp = tempdir().unwrap();
++    let mut dir = Dir::open(tmp.path(), OFlag::O_DIRECTORY | OFlag::O_RDONLY | OFlag::O_CLOEXEC,
++                            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();
++    assert_eq!(entries1, entries2);
++}
++
++#[test]
++fn ebadf() {
++    assert_eq!(Dir::from_fd(-1).unwrap_err(), nix::Error::Sys(nix::errno::Errno::EBADF));
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test_fcntl.rs b/third_party/rust/nix-0.15.0/test/test_fcntl.rs
+new file mode 100644
+index 0000000000000..6b2bbd679fc31
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_fcntl.rs
+@@ -0,0 +1,234 @@
++use nix::Error;
++use nix::errno::*;
++use nix::fcntl::{openat, open, OFlag, readlink, readlinkat, renameat};
++use nix::sys::stat::Mode;
++use nix::unistd::{close, read};
++use tempfile::{self, NamedTempFile};
++use std::fs::File;
++use std::io::prelude::*;
++use std::os::unix::fs;
++
++#[test]
++fn test_openat() {
++    const CONTENTS: &[u8] = b"abcd";
++    let mut tmp = NamedTempFile::new().unwrap();
++    tmp.write_all(CONTENTS).unwrap();
++
++    let dirfd = open(tmp.path().parent().unwrap(),
++                     OFlag::empty(),
++                     Mode::empty()).unwrap();
++    let fd = openat(dirfd,
++                    tmp.path().file_name().unwrap(),
++                    OFlag::O_RDONLY,
++                    Mode::empty()).unwrap();
++
++    let mut buf = [0u8; 1024];
++    assert_eq!(4, read(fd, &mut buf).unwrap());
++    assert_eq!(CONTENTS, &buf[0..4]);
++
++    close(fd).unwrap();
++    close(dirfd).unwrap();
++}
++
++#[test]
++fn test_renameat() {
++    let old_dir = tempfile::tempdir().unwrap();
++    let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
++    let old_path = old_dir.path().join("old");
++    File::create(&old_path).unwrap();
++    let new_dir = tempfile::tempdir().unwrap();
++    let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
++    renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap();
++    assert_eq!(renameat(Some(old_dirfd), "old", Some(new_dirfd), "new").unwrap_err(),
++               Error::Sys(Errno::ENOENT));
++    close(old_dirfd).unwrap();
++    close(new_dirfd).unwrap();
++    assert!(new_dir.path().join("new").exists());
++}
++
++#[test]
++fn test_readlink() {
++    let tempdir = tempfile::tempdir().unwrap();
++    let src = tempdir.path().join("a");
++    let dst = tempdir.path().join("b");
++    println!("a: {:?}, b: {:?}", &src, &dst);
++    fs::symlink(&src.as_path(), &dst.as_path()).unwrap();
++    let dirfd = open(tempdir.path(),
++                     OFlag::empty(),
++                     Mode::empty()).unwrap();
++
++    let mut buf = vec![0; src.to_str().unwrap().len() + 1];
++    assert_eq!(readlink(&dst, &mut buf).unwrap().to_str().unwrap(),
++               src.to_str().unwrap());
++    assert_eq!(readlinkat(dirfd, "b", &mut buf).unwrap().to_str().unwrap(),
++               src.to_str().unwrap());
++}
++
++#[cfg(any(target_os = "linux", target_os = "android"))]
++mod linux_android {
++    use std::io::prelude::*;
++    use std::io::SeekFrom;
++    use std::os::unix::prelude::*;
++
++    use libc::loff_t;
++
++    use nix::fcntl::*;
++    use nix::sys::uio::IoVec;
++    use nix::unistd::{close, pipe, read, write};
++
++    use tempfile::{tempfile, NamedTempFile};
++
++    /// 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
++    /// resulting file is read and should contain the contents `bar`.
++    /// The from_offset should be updated by the call to reflect
++    /// the 3 bytes read (6).
++    ///
++    /// FIXME: This test is disabled for linux based builds, because Travis
++    /// Linux version is too old for `copy_file_range`.
++    #[test]
++    #[ignore]
++    fn test_copy_file_range() {
++        const CONTENTS: &[u8] = b"foobarbaz";
++
++        let mut tmp1 = tempfile().unwrap();
++        let mut tmp2 = tempfile().unwrap();
++
++        tmp1.write_all(CONTENTS).unwrap();
++        tmp1.flush().unwrap();
++
++        let mut from_offset: i64 = 3;
++        copy_file_range(
++            tmp1.as_raw_fd(),
++            Some(&mut from_offset),
++            tmp2.as_raw_fd(),
++            None,
++            3,
++        )
++        .unwrap();
++
++        let mut res: String = String::new();
++        tmp2.seek(SeekFrom::Start(0)).unwrap();
++        tmp2.read_to_string(&mut res).unwrap();
++
++        assert_eq!(res, String::from("bar"));
++        assert_eq!(from_offset, 6);
++    }
++
++    #[test]
++    fn test_splice() {
++        const CONTENTS: &[u8] = b"abcdef123456";
++        let mut tmp = tempfile().unwrap();
++        tmp.write_all(CONTENTS).unwrap();
++
++        let (rd, wr) = pipe().unwrap();
++        let mut offset: loff_t = 5;
++        let res = splice(tmp.as_raw_fd(), Some(&mut offset),
++            wr, None, 2, SpliceFFlags::empty()).unwrap();
++
++        assert_eq!(2, res);
++
++        let mut buf = [0u8; 1024];
++        assert_eq!(2, read(rd, &mut buf).unwrap());
++        assert_eq!(b"f1", &buf[0..2]);
++        assert_eq!(7, offset);
++
++        close(rd).unwrap();
++        close(wr).unwrap();
++    }
++
++    #[test]
++    fn test_tee() {
++        let (rd1, wr1) = pipe().unwrap();
++        let (rd2, wr2) = pipe().unwrap();
++
++        write(wr1, b"abc").unwrap();
++        let res = tee(rd1, wr2, 2, SpliceFFlags::empty()).unwrap();
++
++        assert_eq!(2, res);
++
++        let mut buf = [0u8; 1024];
++
++        // Check the tee'd bytes are at rd2.
++        assert_eq!(2, read(rd2, &mut buf).unwrap());
++        assert_eq!(b"ab", &buf[0..2]);
++
++        // Check all the bytes are still at rd1.
++        assert_eq!(3, read(rd1, &mut buf).unwrap());
++        assert_eq!(b"abc", &buf[0..3]);
++
++        close(rd1).unwrap();
++        close(wr1).unwrap();
++        close(rd2).unwrap();
++        close(wr2).unwrap();
++    }
++
++    #[test]
++    fn test_vmsplice() {
++        let (rd, wr) = pipe().unwrap();
++
++        let buf1 = b"abcdef";
++        let buf2 = b"defghi";
++        let mut iovecs = Vec::with_capacity(2);
++        iovecs.push(IoVec::from_slice(&buf1[0..3]));
++        iovecs.push(IoVec::from_slice(&buf2[0..3]));
++
++        let res = vmsplice(wr, &iovecs[..], SpliceFFlags::empty()).unwrap();
++
++        assert_eq!(6, res);
++
++        // Check the bytes can be read at rd.
++        let mut buf = [0u8; 32];
++        assert_eq!(6, read(rd, &mut buf).unwrap());
++        assert_eq!(b"abcdef", &buf[0..6]);
++
++        close(rd).unwrap();
++        close(wr).unwrap();
++    }
++
++    #[test]
++    fn test_fallocate() {
++        let tmp = NamedTempFile::new().unwrap();
++
++        let fd = tmp.as_raw_fd();
++        fallocate(fd, FallocateFlags::empty(), 0, 100).unwrap();
++
++        // Check if we read exactly 100 bytes
++        let mut buf = [0u8; 200];
++        assert_eq!(100, read(fd, &mut buf).unwrap());
++    }
++}
++
++#[cfg(any(target_os = "linux",
++          target_os = "android",
++          target_os = "emscripten",
++          target_os = "fuchsia",
++          any(target_os = "wasi", target_env = "wasi"),
++          target_env = "uclibc",
++          target_env = "freebsd"))]
++mod test_posix_fadvise {
++
++    use tempfile::NamedTempFile;
++    use std::os::unix::io::{RawFd, AsRawFd};
++    use nix::errno::Errno;
++    use nix::fcntl::*;
++    use nix::unistd::pipe;
++
++    #[test]
++    fn test_success() {
++        let tmp = NamedTempFile::new().unwrap();
++        let fd = tmp.as_raw_fd();
++        let res = posix_fadvise(fd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED).unwrap();
++
++        assert_eq!(res, 0);
++    }
++
++    #[test]
++    fn test_errno() {
++        let (rd, _wr) = pipe().unwrap();
++        let errno = posix_fadvise(rd as RawFd, 0, 100, PosixFadviseAdvice::POSIX_FADV_WILLNEED)
++                                 .unwrap();
++        assert_eq!(errno, Errno::ESPIPE as i32);
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test_kmod/hello_mod/Makefile b/third_party/rust/nix-0.15.0/test/test_kmod/hello_mod/Makefile
+new file mode 100644
+index 0000000000000..74c99b77e96e1
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_kmod/hello_mod/Makefile
+@@ -0,0 +1,7 @@
++obj-m += hello.o
++
++all:
++	make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules
++
++clean:
++	make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean
+diff --git a/third_party/rust/nix-0.15.0/test/test_kmod/hello_mod/hello.c b/third_party/rust/nix-0.15.0/test/test_kmod/hello_mod/hello.c
+new file mode 100644
+index 0000000000000..1c34987d2ac39
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_kmod/hello_mod/hello.c
+@@ -0,0 +1,26 @@
++/*
++ *  SPDX-License-Identifier: GPL-2.0+ or MIT
++ */
++#include <linux/module.h>
++#include <linux/kernel.h>
++
++static int number= 1;
++static char *who = "World";
++
++module_param(number, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
++MODULE_PARM_DESC(myint, "Just some number");
++module_param(who, charp, 0000);
++MODULE_PARM_DESC(who, "Whot to greet");
++
++int init_module(void)
++{
++	printk(KERN_INFO "Hello %s (%d)!\n", who, number);
++	return 0;
++}
++
++void cleanup_module(void)
++{
++	printk(KERN_INFO "Goodbye %s (%d)!\n", who, number);
++}
++
++MODULE_LICENSE("Dual MIT/GPL");
+diff --git a/third_party/rust/nix-0.15.0/test/test_kmod/mod.rs b/third_party/rust/nix-0.15.0/test/test_kmod/mod.rs
+new file mode 100644
+index 0000000000000..ad406357b06d2
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_kmod/mod.rs
+@@ -0,0 +1,166 @@
++use std::fs::copy;
++use std::path::PathBuf;
++use std::process::Command;
++use tempfile::{tempdir, TempDir};
++
++fn compile_kernel_module() -> (PathBuf, String, TempDir) {
++    let _m = ::FORK_MTX
++        .lock()
++        .expect("Mutex got poisoned by another test");
++
++    let tmp_dir = tempdir().expect("unable to create temporary build directory");
++
++    copy(
++        "test/test_kmod/hello_mod/hello.c",
++        &tmp_dir.path().join("hello.c"),
++    ).expect("unable to copy hello.c to temporary build directory");
++    copy(
++        "test/test_kmod/hello_mod/Makefile",
++        &tmp_dir.path().join("Makefile"),
++    ).expect("unable to copy Makefile to temporary build directory");
++
++    let status = Command::new("make")
++        .current_dir(tmp_dir.path())
++        .status()
++        .expect("failed to run make");
++
++    assert!(status.success());
++
++    // Return the relative path of the build kernel module
++    (tmp_dir.path().join("hello.ko"), "hello".to_owned(), tmp_dir)
++}
++
++use nix::errno::Errno;
++use nix::kmod::{delete_module, DeleteModuleFlags};
++use nix::kmod::{finit_module, init_module, ModuleInitFlags};
++use nix::Error;
++use std::ffi::CString;
++use std::fs::File;
++use std::io::Read;
++
++#[test]
++fn test_finit_and_delete_module() {
++    require_capability!(CAP_SYS_MODULE);
++    let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++    let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
++
++    let f = File::open(kmod_path).expect("unable to open kernel module");
++    finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty())
++        .expect("unable to load kernel module");
++
++    delete_module(
++        &CString::new(kmod_name).unwrap(),
++        DeleteModuleFlags::empty(),
++    ).expect("unable to unload kernel module");
++}
++
++#[test]
++fn test_finit_and_delete_modul_with_params() {
++    require_capability!(CAP_SYS_MODULE);
++    let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++    let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
++
++    let f = File::open(kmod_path).expect("unable to open kernel module");
++    finit_module(
++        &f,
++        &CString::new("who=Rust number=2018").unwrap(),
++        ModuleInitFlags::empty(),
++    ).expect("unable to load kernel module");
++
++    delete_module(
++        &CString::new(kmod_name).unwrap(),
++        DeleteModuleFlags::empty(),
++    ).expect("unable to unload kernel module");
++}
++
++#[test]
++fn test_init_and_delete_module() {
++    require_capability!(CAP_SYS_MODULE);
++    let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++    let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
++
++    let mut f = File::open(kmod_path).expect("unable to open kernel module");
++    let mut contents: Vec<u8> = Vec::new();
++    f.read_to_end(&mut contents)
++        .expect("unable to read kernel module content to buffer");
++    init_module(&mut contents, &CString::new("").unwrap()).expect("unable to load kernel module");
++
++    delete_module(
++        &CString::new(kmod_name).unwrap(),
++        DeleteModuleFlags::empty(),
++    ).expect("unable to unload kernel module");
++}
++
++#[test]
++fn test_init_and_delete_module_with_params() {
++    require_capability!(CAP_SYS_MODULE);
++    let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++    let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
++
++    let mut f = File::open(kmod_path).expect("unable to open kernel module");
++    let mut contents: Vec<u8> = Vec::new();
++    f.read_to_end(&mut contents)
++        .expect("unable to read kernel module content to buffer");
++    init_module(&mut contents, &CString::new("who=Nix number=2015").unwrap())
++        .expect("unable to load kernel module");
++
++    delete_module(
++        &CString::new(kmod_name).unwrap(),
++        DeleteModuleFlags::empty(),
++    ).expect("unable to unload kernel module");
++}
++
++#[test]
++fn test_finit_module_invalid() {
++    require_capability!(CAP_SYS_MODULE);
++    let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++    let kmod_path = "/dev/zero";
++
++    let f = File::open(kmod_path).expect("unable to open kernel module");
++    let result = finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty());
++
++    assert_eq!(result.unwrap_err(), Error::Sys(Errno::EINVAL));
++}
++
++#[test]
++fn test_finit_module_twice_and_delete_module() {
++    require_capability!(CAP_SYS_MODULE);
++    let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++    let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
++
++    let f = File::open(kmod_path).expect("unable to open kernel module");
++    finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty())
++        .expect("unable to load kernel module");
++
++    let result = finit_module(&f, &CString::new("").unwrap(), ModuleInitFlags::empty());
++
++    assert_eq!(result.unwrap_err(), Error::Sys(Errno::EEXIST));
++
++    delete_module(
++        &CString::new(kmod_name).unwrap(),
++        DeleteModuleFlags::empty(),
++    ).expect("unable to unload kernel module");
++}
++
++#[test]
++fn test_delete_module_not_loaded() {
++    require_capability!(CAP_SYS_MODULE);
++    let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++    let result = delete_module(&CString::new("hello").unwrap(), DeleteModuleFlags::empty());
++
++    assert_eq!(result.unwrap_err(), Error::Sys(Errno::ENOENT));
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test_mount.rs b/third_party/rust/nix-0.15.0/test/test_mount.rs
+new file mode 100644
+index 0000000000000..d2e08bc42855d
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_mount.rs
+@@ -0,0 +1,238 @@
++// 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
++// without root.
++
++extern crate libc;
++extern crate nix;
++extern crate tempfile;
++
++#[cfg(target_os = "linux")]
++mod test_mount {
++    use std::fs::{self, File};
++    use std::io::{self, Read, Write};
++    use std::os::unix::fs::OpenOptionsExt;
++    use std::os::unix::fs::PermissionsExt;
++    use std::process::{self, Command};
++
++    use libc::{EACCES, EROFS};
++
++    use nix::errno::Errno;
++    use nix::mount::{mount, umount, MsFlags};
++    use nix::sched::{unshare, CloneFlags};
++    use nix::sys::stat::{self, Mode};
++    use nix::unistd::getuid;
++
++    use tempfile;
++
++    static SCRIPT_CONTENTS: &'static [u8] = b"#!/bin/sh
++exit 23";
++
++    const EXPECTED_STATUS: i32 = 23;
++
++    const NONE: Option<&'static [u8]> = None;
++    pub fn test_mount_tmpfs_without_flags_allows_rwx() {
++        let tempdir = tempfile::tempdir().unwrap();
++
++        mount(NONE,
++              tempdir.path(),
++              Some(b"tmpfs".as_ref()),
++              MsFlags::empty(),
++              NONE)
++            .unwrap_or_else(|e| panic!("mount failed: {}", e));
++
++        let test_path = tempdir.path().join("test");
++
++        // Verify write.
++        fs::OpenOptions::new()
++            .create(true)
++            .write(true)
++            .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
++            .open(&test_path)
++            .or_else(|e|
++                if Errno::from_i32(e.raw_os_error().unwrap()) == Errno::EOVERFLOW {
++                    // Skip tests on certain Linux kernels which have a bug
++                    // regarding tmpfs in namespaces.
++                    // Ubuntu 14.04 and 16.04 are known to be affected; 16.10 is
++                    // not.  There is no legitimate reason for open(2) to return
++                    // EOVERFLOW here.
++                    // https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1659087
++                    let stderr = io::stderr();
++                    let mut handle = stderr.lock();
++                    writeln!(handle, "Buggy Linux kernel detected.  Skipping test.")
++                    .unwrap();
++                    process::exit(0);
++               } else {
++                   panic!("open failed: {}", e);
++               }
++            )
++            .and_then(|mut f| f.write(SCRIPT_CONTENTS))
++            .unwrap_or_else(|e| panic!("write failed: {}", e));
++
++        // Verify read.
++        let mut buf = Vec::new();
++        File::open(&test_path)
++            .and_then(|mut f| f.read_to_end(&mut buf))
++            .unwrap_or_else(|e| panic!("read failed: {}", e));
++        assert_eq!(buf, SCRIPT_CONTENTS);
++
++        // Verify execute.
++        assert_eq!(EXPECTED_STATUS,
++                   Command::new(&test_path)
++                       .status()
++                       .unwrap_or_else(|e| panic!("exec failed: {}", e))
++                       .code()
++                       .unwrap_or_else(|| panic!("child killed by signal")));
++
++        umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {}", e));
++    }
++
++    pub fn test_mount_rdonly_disallows_write() {
++        let tempdir = tempfile::tempdir().unwrap();
++
++        mount(NONE,
++              tempdir.path(),
++              Some(b"tmpfs".as_ref()),
++              MsFlags::MS_RDONLY,
++              NONE)
++            .unwrap_or_else(|e| panic!("mount failed: {}", e));
++
++        // EROFS: Read-only file system
++        assert_eq!(EROFS as i32,
++                   File::create(tempdir.path().join("test")).unwrap_err().raw_os_error().unwrap());
++
++        umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {}", e));
++    }
++
++    pub fn test_mount_noexec_disallows_exec() {
++        let tempdir = tempfile::tempdir().unwrap();
++
++        mount(NONE,
++              tempdir.path(),
++              Some(b"tmpfs".as_ref()),
++              MsFlags::MS_NOEXEC,
++              NONE)
++            .unwrap_or_else(|e| panic!("mount failed: {}", e));
++
++        let test_path = tempdir.path().join("test");
++
++        fs::OpenOptions::new()
++            .create(true)
++            .write(true)
++            .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
++            .open(&test_path)
++            .and_then(|mut f| f.write(SCRIPT_CONTENTS))
++            .unwrap_or_else(|e| panic!("write failed: {}", e));
++
++        // Verify that we cannot execute despite a+x permissions being set.
++        let mode = stat::Mode::from_bits_truncate(fs::metadata(&test_path)
++                                                      .map(|md| md.permissions().mode())
++                                                      .unwrap_or_else(|e| {
++                                                          panic!("metadata failed: {}", e)
++                                                      }));
++
++        assert!(mode.contains(Mode::S_IXUSR | Mode::S_IXGRP | Mode::S_IXOTH),
++                "{:?} did not have execute permissions",
++                &test_path);
++
++        // EACCES: Permission denied
++        assert_eq!(EACCES as i32,
++                   Command::new(&test_path).status().unwrap_err().raw_os_error().unwrap());
++
++        umount(tempdir.path()).unwrap_or_else(|e| panic!("umount failed: {}", e));
++    }
++
++    pub fn test_mount_bind() {
++        let tempdir = tempfile::tempdir().unwrap();
++        let file_name = "test";
++
++        {
++            let mount_point = tempfile::tempdir().unwrap();
++
++            mount(Some(tempdir.path()),
++                  mount_point.path(),
++                  NONE,
++                  MsFlags::MS_BIND,
++                  NONE)
++                .unwrap_or_else(|e| panic!("mount failed: {}", e));
++
++            fs::OpenOptions::new()
++                .create(true)
++                .write(true)
++                .mode((Mode::S_IRWXU | Mode::S_IRWXG | Mode::S_IRWXO).bits())
++                .open(mount_point.path().join(file_name))
++                .and_then(|mut f| f.write(SCRIPT_CONTENTS))
++                .unwrap_or_else(|e| panic!("write failed: {}", e));
++
++            umount(mount_point.path()).unwrap_or_else(|e| panic!("umount failed: {}", e));
++        }
++
++        // Verify the file written in the mount shows up in source directory, even
++        // after unmounting.
++
++        let mut buf = Vec::new();
++        File::open(tempdir.path().join(file_name))
++            .and_then(|mut f| f.read_to_end(&mut buf))
++            .unwrap_or_else(|e| panic!("read failed: {}", e));
++        assert_eq!(buf, SCRIPT_CONTENTS);
++    }
++
++    pub fn setup_namespaces() {
++        // Hold on to the uid in the parent namespace.
++        let uid = getuid();
++
++        unshare(CloneFlags::CLONE_NEWNS | CloneFlags::CLONE_NEWUSER).unwrap_or_else(|e| {
++            let stderr = io::stderr();
++            let mut handle = stderr.lock();
++            writeln!(handle,
++                     "unshare failed: {}. Are unprivileged user namespaces available?",
++                     e).unwrap();
++            writeln!(handle, "mount is not being tested").unwrap();
++            // Exit with success because not all systems support unprivileged user namespaces, and
++            // that's not what we're testing for.
++            process::exit(0);
++        });
++
++        // Map user as uid 1000.
++        fs::OpenOptions::new()
++            .write(true)
++            .open("/proc/self/uid_map")
++            .and_then(|mut f| f.write(format!("1000 {} 1\n", uid).as_bytes()))
++            .unwrap_or_else(|e| panic!("could not write uid map: {}", e));
++    }
++}
++
++
++// Test runner
++
++/// Mimic normal test output (hackishly).
++#[cfg(target_os = "linux")]
++macro_rules! run_tests {
++    ( $($test_fn:ident),* ) => {{
++        println!();
++
++        $(
++            print!("test test_mount::{} ... ", stringify!($test_fn));
++            $test_fn();
++            println!("ok");
++        )*
++
++        println!();
++    }}
++}
++
++#[cfg(target_os = "linux")]
++fn main() {
++    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};
++    setup_namespaces();
++
++    run_tests!(test_mount_tmpfs_without_flags_allows_rwx,
++               test_mount_rdonly_disallows_write,
++               test_mount_noexec_disallows_exec,
++               test_mount_bind);
++}
++
++#[cfg(not(target_os = "linux"))]
++fn main() {}
+diff --git a/third_party/rust/nix-0.15.0/test/test_mq.rs b/third_party/rust/nix-0.15.0/test/test_mq.rs
+new file mode 100644
+index 0000000000000..caac4fc261cd6
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_mq.rs
+@@ -0,0 +1,152 @@
++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::{MqAttr, MQ_OFlag};
++use nix::sys::stat::Mode;
++
++#[test]
++fn test_mq_send_and_receive() {
++    const MSG_SIZE: c_long =  32;
++    let attr =  MqAttr::new(0, 10, MSG_SIZE, 0);
++    let mq_name= &CString::new(b"/a_nix_test_queue".as_ref()).unwrap();
++
++    let oflag0 = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
++    let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
++    let r0 = mq_open(mq_name, oflag0, mode, Some(&attr));
++    if let Err(Sys(ENOSYS)) = r0 {
++        println!("message queues not supported or module not loaded?");
++        return;
++    };
++    let mqd0 = r0.unwrap();
++    let msg_to_send = "msg_1";
++    mq_send(mqd0, msg_to_send.as_bytes(), 1).unwrap();
++
++    let oflag1 = MQ_OFlag::O_CREAT | MQ_OFlag::O_RDONLY;
++    let mqd1 = mq_open(mq_name, oflag1, mode, Some(&attr)).unwrap();
++    let mut buf = [0u8; 32];
++    let mut prio = 0u32;
++    let len = mq_receive(mqd1, &mut buf, &mut prio).unwrap();
++    assert!(prio == 1);
++
++    mq_close(mqd1).unwrap();
++    mq_close(mqd0).unwrap();
++    assert_eq!(msg_to_send, str::from_utf8(&buf[0..len]).unwrap());
++}
++
++
++#[test]
++#[cfg(not(any(target_os = "netbsd")))]
++fn test_mq_getattr() {
++    use nix::mqueue::mq_getattr;
++    const MSG_SIZE: c_long =  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;
++    let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
++    let r = mq_open(mq_name, oflag, mode, Some(&initial_attr));
++    if let Err(Sys(ENOSYS)) = r {
++        println!("message queues not supported or module not loaded?");
++        return;
++    };
++    let mqd = r.unwrap();
++
++    let read_attr = mq_getattr(mqd).unwrap();
++    assert_eq!(read_attr, initial_attr);
++    mq_close(mqd).unwrap();
++}
++
++// FIXME: Fix failures for mips in QEMU
++#[test]
++#[cfg(not(any(target_os = "netbsd")))]
++#[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;
++    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;
++    let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
++    let r = mq_open(mq_name, oflag, mode, Some(&initial_attr));
++    if let Err(Sys(ENOSYS)) = r {
++        println!("message queues not supported or module not loaded?");
++        return;
++    };
++    let mqd = r.unwrap();
++
++    let new_attr =  MqAttr::new(0, 20, MSG_SIZE * 2, 100);
++    let old_attr = mq_setattr(mqd, &new_attr).unwrap();
++    assert_eq!(old_attr, initial_attr);
++
++    let new_attr_get = mq_getattr(mqd).unwrap();
++    // The following tests make sense. No changes here because according to the Linux man page only
++    // 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);
++    mq_setattr(mqd, &new_attr_non_blocking).unwrap();
++    let new_attr_get = mq_getattr(mqd).unwrap();
++
++    // now the O_NONBLOCK flag has been set
++    assert_ne!(new_attr_get, initial_attr);
++    assert_eq!(new_attr_get, new_attr_non_blocking);
++    mq_close(mqd).unwrap();
++}
++
++// FIXME: Fix failures for mips in QEMU
++#[test]
++#[cfg(not(any(target_os = "netbsd")))]
++#[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;
++    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;
++    let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
++    let r = mq_open(mq_name, oflag, mode, Some(&initial_attr));
++    if let Err(Sys(ENOSYS)) = r {
++        println!("message queues not supported or module not loaded?");
++        return;
++    };
++    let mqd = r.unwrap();
++    mq_set_nonblock(mqd).unwrap();
++    let new_attr = mq_getattr(mqd);
++    assert!(new_attr.unwrap().flags() == MQ_OFlag::O_NONBLOCK.bits() as c_long);
++    mq_remove_nonblock(mqd).unwrap();
++    let new_attr = mq_getattr(mqd);
++    assert!(new_attr.unwrap().flags() == 0);
++    mq_close(mqd).unwrap();
++}
++
++#[test]
++#[cfg(not(any(target_os = "netbsd")))]
++fn test_mq_unlink() {
++    use nix::mqueue::mq_unlink;
++    const MSG_SIZE: c_long =  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();
++    let oflag = MQ_OFlag::O_CREAT | MQ_OFlag::O_WRONLY;
++    let mode = Mode::S_IWUSR | Mode::S_IRUSR | Mode::S_IRGRP | Mode::S_IROTH;
++    let r = mq_open(mq_name_opened, oflag, mode, Some(&initial_attr));
++    if let Err(Sys(ENOSYS)) = r {
++        println!("message queues not supported or module not loaded?");
++        return;
++    };
++    let mqd = r.unwrap();
++
++    let res_unlink = mq_unlink(mq_name_opened);
++    assert!(res_unlink == Ok(()) );
++
++    let res_unlink_not_opened = mq_unlink(mq_name_not_opened);
++    assert!(res_unlink_not_opened == Err(Sys(ENOENT)) );
++
++    mq_close(mqd).unwrap();
++    let res_unlink_after_close = mq_unlink(mq_name_opened);
++    assert!(res_unlink_after_close == Err(Sys(ENOENT)) );
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test_net.rs b/third_party/rust/nix-0.15.0/test/test_net.rs
+new file mode 100644
+index 0000000000000..b8940e718bdf3
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_net.rs
+@@ -0,0 +1,12 @@
++use nix::net::if_::*;
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++const LOOPBACK: &[u8] = b"lo";
++
++#[cfg(not(any(target_os = "android", target_os = "linux")))]
++const LOOPBACK: &[u8] = b"lo0";
++
++#[test]
++fn test_if_nametoindex() {
++    assert!(if_nametoindex(&LOOPBACK[..]).is_ok());
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test_nix_path.rs b/third_party/rust/nix-0.15.0/test/test_nix_path.rs
+new file mode 100644
+index 0000000000000..e69de29bb2d1d
+diff --git a/third_party/rust/nix-0.15.0/test/test_poll.rs b/third_party/rust/nix-0.15.0/test/test_poll.rs
+new file mode 100644
+index 0000000000000..aef40e4792b5a
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_poll.rs
+@@ -0,0 +1,50 @@
++use nix::poll::{PollFlags, poll, PollFd};
++use nix::unistd::{write, pipe};
++
++#[test]
++fn test_poll() {
++    let (r, w) = pipe().unwrap();
++    let mut fds = [PollFd::new(r, PollFlags::POLLIN)];
++
++    // Poll an idle pipe.  Should timeout
++    let nfds = poll(&mut fds, 100).unwrap();
++    assert_eq!(nfds, 0);
++    assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN));
++
++    write(w, b".").unwrap();
++
++    // Poll a readable pipe.  Should return an event.
++    let nfds = poll(&mut fds, 100).unwrap();
++    assert_eq!(nfds, 1);
++    assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN));
++}
++
++// ppoll(2) is the same as poll except for how it handles timeouts and signals.
++// Repeating the test for poll(2) should be sufficient to check that our
++// bindings are correct.
++#[cfg(any(target_os = "android",
++          target_os = "dragonfly",
++          target_os = "freebsd",
++          target_os = "linux"))]
++#[test]
++fn test_ppoll() {
++    use nix::poll::ppoll;
++    use nix::sys::signal::SigSet;
++    use nix::sys::time::{TimeSpec, TimeValLike};
++
++    let timeout = TimeSpec::milliseconds(1);
++    let (r, w) = pipe().unwrap();
++    let mut fds = [PollFd::new(r, PollFlags::POLLIN)];
++
++    // Poll an idle pipe.  Should timeout
++    let nfds = ppoll(&mut fds, timeout, SigSet::empty()).unwrap();
++    assert_eq!(nfds, 0);
++    assert!(!fds[0].revents().unwrap().contains(PollFlags::POLLIN));
++
++    write(w, b".").unwrap();
++
++    // Poll a readable pipe.  Should return an event.
++    let nfds = ppoll(&mut fds, timeout, SigSet::empty()).unwrap();
++    assert_eq!(nfds, 1);
++    assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN));
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test_pty.rs b/third_party/rust/nix-0.15.0/test/test_pty.rs
+new file mode 100644
+index 0000000000000..476b15c10128c
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_pty.rs
+@@ -0,0 +1,235 @@
++use std::io::Write;
++use std::path::Path;
++use std::os::unix::prelude::*;
++use tempfile::tempfile;
++
++use libc::{_exit, STDOUT_FILENO};
++use nix::fcntl::{OFlag, open};
++use nix::pty::*;
++use nix::sys::stat;
++use nix::sys::termios::*;
++use nix::unistd::{write, close, pause};
++
++/// Regression test for Issue #659
++/// This is the correct way to explicitly close a `PtyMaster`
++#[test]
++fn test_explicit_close() {
++    let mut f = {
++        let m = posix_openpt(OFlag::O_RDWR).unwrap();
++        close(m.into_raw_fd()).unwrap();
++        tempfile().unwrap()
++    };
++    // This should work.  But if there's been a double close, then it will
++    // return EBADF
++    f.write_all(b"whatever").unwrap();
++}
++
++/// Test equivalence of `ptsname` and `ptsname_r`
++#[test]
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn test_ptsname_equivalence() {
++    let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++
++    // Open a new PTTY master
++    let master_fd = posix_openpt(OFlag::O_RDWR).unwrap();
++    assert!(master_fd.as_raw_fd() > 0);
++
++    // Get the name of the slave
++    let slave_name = unsafe { ptsname(&master_fd) }.unwrap() ;
++    let slave_name_r = ptsname_r(&master_fd).unwrap();
++    assert_eq!(slave_name, slave_name_r);
++}
++
++/// Test data copying of `ptsname`
++// TODO need to run in a subprocess, since ptsname is non-reentrant
++#[test]
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn test_ptsname_copy() {
++    let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++
++    // Open a new PTTY master
++    let master_fd = posix_openpt(OFlag::O_RDWR).unwrap();
++    assert!(master_fd.as_raw_fd() > 0);
++
++    // Get the name of the slave
++    let slave_name1 = unsafe { ptsname(&master_fd) }.unwrap();
++    let slave_name2 = unsafe { ptsname(&master_fd) }.unwrap();
++    assert!(slave_name1 == slave_name2);
++    // Also make sure that the string was actually copied and they point to different parts of
++    // memory.
++    assert!(slave_name1.as_ptr() != slave_name2.as_ptr());
++}
++
++/// Test data copying of `ptsname_r`
++#[test]
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn test_ptsname_r_copy() {
++    // Open a new PTTY master
++    let master_fd = posix_openpt(OFlag::O_RDWR).unwrap();
++    assert!(master_fd.as_raw_fd() > 0);
++
++    // Get the name of the slave
++    let slave_name1 = ptsname_r(&master_fd).unwrap();
++    let slave_name2 = ptsname_r(&master_fd).unwrap();
++    assert!(slave_name1 == slave_name2);
++    assert!(slave_name1.as_ptr() != slave_name2.as_ptr());
++}
++
++/// Test that `ptsname` returns different names for different devices
++#[test]
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn test_ptsname_unique() {
++    let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++
++    // Open a new PTTY master
++    let master1_fd = posix_openpt(OFlag::O_RDWR).unwrap();
++    assert!(master1_fd.as_raw_fd() > 0);
++
++    // Open a second PTTY master
++    let master2_fd = posix_openpt(OFlag::O_RDWR).unwrap();
++    assert!(master2_fd.as_raw_fd() > 0);
++
++    // Get the name of the slave
++    let slave_name1 = unsafe { ptsname(&master1_fd) }.unwrap();
++    let slave_name2 = unsafe { ptsname(&master2_fd) }.unwrap();
++    assert!(slave_name1 != slave_name2);
++}
++
++/// Test opening a master/slave PTTY pair
++///
++/// This is a single larger test because much of these functions aren't useful by themselves. So for
++/// this test we perform the basic act of getting a file handle for a connect master/slave PTTY
++/// pair.
++#[test]
++fn test_open_ptty_pair() {
++    let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++
++    // Open a new PTTY master
++    let master_fd = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed");
++    assert!(master_fd.as_raw_fd() > 0);
++
++    // Allow a slave to be generated for it
++    grantpt(&master_fd).expect("grantpt failed");
++    unlockpt(&master_fd).expect("unlockpt failed");
++
++    // Get the name of the slave
++    let slave_name = unsafe { ptsname(&master_fd) }.expect("ptsname failed");
++
++    // Open the slave device
++    let slave_fd = open(Path::new(&slave_name), OFlag::O_RDWR, stat::Mode::empty()).unwrap();
++    assert!(slave_fd > 0);
++}
++
++#[test]
++fn test_openpty() {
++    // openpty uses ptname(3) internally
++    let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++
++    let pty = openpty(None, None).unwrap();
++    assert!(pty.master > 0);
++    assert!(pty.slave > 0);
++
++    // Writing to one should be readable on the other one
++    let string = "foofoofoo\n";
++    let mut buf = [0u8; 10];
++    write(pty.master, string.as_bytes()).unwrap();
++    ::read_exact(pty.slave, &mut buf);
++
++    assert_eq!(&buf, string.as_bytes());
++
++    // Read the echo as well
++    let echoed_string = "foofoofoo\r\n";
++    let mut buf = [0u8; 11];
++    ::read_exact(pty.master, &mut buf);
++    assert_eq!(&buf, echoed_string.as_bytes());
++
++    let string2 = "barbarbarbar\n";
++    let echoed_string2 = "barbarbarbar\r\n";
++    let mut buf = [0u8; 14];
++    write(pty.slave, string2.as_bytes()).unwrap();
++    ::read_exact(pty.master, &mut buf);
++
++    assert_eq!(&buf, echoed_string2.as_bytes());
++
++    close(pty.master).unwrap();
++    close(pty.slave).unwrap();
++}
++
++#[test]
++fn test_openpty_with_termios() {
++    // openpty uses ptname(3) internally
++    let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++
++    // Open one pty to get attributes for the second one
++    let mut termios = {
++        let pty = openpty(None, None).unwrap();
++        assert!(pty.master > 0);
++        assert!(pty.slave > 0);
++        let termios = tcgetattr(pty.master).unwrap();
++        close(pty.master).unwrap();
++        close(pty.slave).unwrap();
++        termios
++    };
++    // Make sure newlines are not transformed so the data is preserved when sent.
++    termios.output_flags.remove(OutputFlags::ONLCR);
++
++    let pty = openpty(None, &termios).unwrap();
++    // Must be valid file descriptors
++    assert!(pty.master > 0);
++    assert!(pty.slave > 0);
++
++    // Writing to one should be readable on the other one
++    let string = "foofoofoo\n";
++    let mut buf = [0u8; 10];
++    write(pty.master, string.as_bytes()).unwrap();
++    ::read_exact(pty.slave, &mut buf);
++
++    assert_eq!(&buf, string.as_bytes());
++
++    // read the echo as well
++    let echoed_string = "foofoofoo\n";
++    ::read_exact(pty.master, &mut buf);
++    assert_eq!(&buf, echoed_string.as_bytes());
++
++    let string2 = "barbarbarbar\n";
++    let echoed_string2 = "barbarbarbar\n";
++    let mut buf = [0u8; 13];
++    write(pty.slave, string2.as_bytes()).unwrap();
++    ::read_exact(pty.master, &mut buf);
++
++    assert_eq!(&buf, echoed_string2.as_bytes());
++
++    close(pty.master).unwrap();
++    close(pty.slave).unwrap();
++}
++
++#[test]
++fn test_forkpty() {
++    use nix::unistd::ForkResult::*;
++    use nix::sys::signal::*;
++    use nix::sys::wait::wait;
++    // forkpty calls openpty which uses ptname(3) internally.
++    let _m0 = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++    // forkpty spawns a child process
++    let _m1 = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++
++    let string = "naninani\n";
++    let echoed_string = "naninani\r\n";
++    let pty = forkpty(None, None).unwrap();
++    match pty.fork_result {
++        Child => {
++            write(STDOUT_FILENO, string.as_bytes()).unwrap();
++            pause();  // we need the child to stay alive until the parent calls read
++            unsafe { _exit(0); }
++        },
++        Parent { child } => {
++            let mut buf = [0u8; 10];
++            assert!(child.as_raw() > 0);
++            ::read_exact(pty.master, &mut buf);
++            kill(child, SIGTERM).unwrap();
++            wait().unwrap(); // keep other tests using generic wait from getting our child
++            assert_eq!(&buf, echoed_string.as_bytes());
++            close(pty.master).unwrap();
++        },
++    }
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test_ptymaster_drop.rs b/third_party/rust/nix-0.15.0/test/test_ptymaster_drop.rs
+new file mode 100644
+index 0000000000000..9b59d66435ed0
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_ptymaster_drop.rs
+@@ -0,0 +1,21 @@
++extern crate nix;
++
++use nix::fcntl::OFlag;
++use nix::pty::*;
++use nix::unistd::close;
++use std::os::unix::io::AsRawFd;
++
++/// Regression test for Issue #659
++/// `PtyMaster` should panic rather than double close the file descriptor
++/// This must run in its own test process because it deliberately creates a race
++/// condition.
++#[test]
++#[should_panic(expected = "Closing an invalid file descriptor!")]
++// In Travis on i686-unknown-linux-musl, this test gets SIGABRT.  I don't know
++// why.  It doesn't happen on any other target, and it doesn't happen on my PC.
++#[cfg_attr(all(target_env = "musl", target_arch = "x86"), ignore)]
++fn test_double_close() {
++    let m = posix_openpt(OFlag::O_RDWR).unwrap();
++    close(m.as_raw_fd()).unwrap();
++    drop(m);            // should panic here
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test_sendfile.rs b/third_party/rust/nix-0.15.0/test/test_sendfile.rs
+new file mode 100644
+index 0000000000000..3bc7932f4c84f
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_sendfile.rs
+@@ -0,0 +1,129 @@
++use std::io::prelude::*;
++use std::os::unix::prelude::*;
++
++use libc::off_t;
++use nix::sys::sendfile::*;
++use tempfile::tempfile;
++
++cfg_if! {
++    if #[cfg(any(target_os = "android", target_os = "linux"))] {
++        use nix::unistd::{close, pipe, read};
++    } else if #[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))] {
++        use std::net::Shutdown;
++        use std::os::unix::net::UnixStream;
++    }
++}
++
++#[cfg(any(target_os = "android", target_os = "linux"))]
++#[test]
++fn test_sendfile_linux() {
++    const CONTENTS: &[u8] = b"abcdef123456";
++    let mut tmp = tempfile().unwrap();
++    tmp.write_all(CONTENTS).unwrap();
++
++    let (rd, wr) = pipe().unwrap();
++    let mut offset: off_t = 5;
++    let res = sendfile(wr, tmp.as_raw_fd(), Some(&mut offset), 2).unwrap();
++
++    assert_eq!(2, res);
++
++    let mut buf = [0u8; 1024];
++    assert_eq!(2, read(rd, &mut buf).unwrap());
++    assert_eq!(b"f1", &buf[0..2]);
++    assert_eq!(7, offset);
++
++    close(rd).unwrap();
++    close(wr).unwrap();
++}
++
++#[cfg(target_os = "freebsd")]
++#[test]
++fn test_sendfile_freebsd() {
++    // Declare the content
++    let header_strings = vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
++    let body = "Xabcdef123456";
++    let body_offset = 1;
++    let trailer_strings = vec!["\n", "Served by Make Believe\n"];
++
++    // Write the body to a file
++    let mut tmp = tempfile().unwrap();
++    tmp.write_all(body.as_bytes()).unwrap();
++
++    // Prepare headers and trailers for sendfile
++    let headers: Vec<&[u8]> = header_strings.iter().map(|s| s.as_bytes()).collect();
++    let trailers: Vec<&[u8]> = trailer_strings.iter().map(|s| s.as_bytes()).collect();
++
++    // Prepare socket pair
++    let (mut rd, wr) = UnixStream::pair().unwrap();
++
++    // Call the test method
++    let (res, bytes_written) = sendfile(
++        tmp.as_raw_fd(),
++        wr.as_raw_fd(),
++        body_offset as off_t,
++        None,
++        Some(headers.as_slice()),
++        Some(trailers.as_slice()),
++        SfFlags::empty(),
++        0,
++    );
++    assert!(res.is_ok());
++    wr.shutdown(Shutdown::Both).unwrap();
++
++    // Prepare the expected result
++    let expected_string =
++        header_strings.concat() + &body[body_offset..] + &trailer_strings.concat();
++
++    // Verify the message that was sent
++    assert_eq!(bytes_written as usize, expected_string.as_bytes().len());
++
++    let mut read_string = String::new();
++    let bytes_read = rd.read_to_string(&mut read_string).unwrap();
++    assert_eq!(bytes_written as usize, bytes_read);
++    assert_eq!(expected_string, read_string);
++}
++
++#[cfg(any(target_os = "ios", target_os = "macos"))]
++#[test]
++fn test_sendfile_darwin() {
++    // Declare the content
++    let header_strings = vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
++    let body = "Xabcdef123456";
++    let body_offset = 1;
++    let trailer_strings = vec!["\n", "Served by Make Believe\n"];
++
++    // Write the body to a file
++    let mut tmp = tempfile().unwrap();
++    tmp.write_all(body.as_bytes()).unwrap();
++
++    // Prepare headers and trailers for sendfile
++    let headers: Vec<&[u8]> = header_strings.iter().map(|s| s.as_bytes()).collect();
++    let trailers: Vec<&[u8]> = trailer_strings.iter().map(|s| s.as_bytes()).collect();
++
++    // Prepare socket pair
++    let (mut rd, wr) = UnixStream::pair().unwrap();
++
++    // Call the test method
++    let (res, bytes_written) = sendfile(
++        tmp.as_raw_fd(),
++        wr.as_raw_fd(),
++        body_offset as off_t,
++        None,
++        Some(headers.as_slice()),
++        Some(trailers.as_slice()),
++    );
++    assert!(res.is_ok());
++    wr.shutdown(Shutdown::Both).unwrap();
++
++    // Prepare the expected result
++    let expected_string =
++        header_strings.concat() + &body[body_offset..] + &trailer_strings.concat();
++
++    // Verify the message that was sent
++    assert_eq!(bytes_written as usize, expected_string.as_bytes().len());
++
++    let mut read_string = String::new();
++    let bytes_read = rd.read_to_string(&mut read_string).unwrap();
++    assert_eq!(bytes_written as usize, bytes_read);
++    assert_eq!(expected_string, read_string);
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test_stat.rs b/third_party/rust/nix-0.15.0/test/test_stat.rs
+new file mode 100644
+index 0000000000000..1173455fae8db
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_stat.rs
+@@ -0,0 +1,296 @@
++use std::fs::{self, File};
++use std::os::unix::fs::{symlink, PermissionsExt};
++use std::os::unix::prelude::AsRawFd;
++use std::time::{Duration, UNIX_EPOCH};
++use std::path::Path;
++
++#[cfg(not(any(target_os = "netbsd")))]
++use libc::{S_IFMT, S_IFLNK, mode_t};
++
++use nix::{fcntl, Error};
++use nix::errno::{Errno};
++use nix::sys::stat::{self, fchmod, fchmodat, futimens, stat, utimes, utimensat, mkdirat};
++#[cfg(any(target_os = "linux",
++          target_os = "haiku",
++          target_os = "ios",
++          target_os = "macos",
++          target_os = "freebsd",
++          target_os = "netbsd"))]
++use nix::sys::stat::lutimes;
++use nix::sys::stat::{Mode, FchmodatFlags, UtimensatFlags};
++
++#[cfg(not(any(target_os = "netbsd")))]
++use nix::sys::stat::FileStat;
++
++use nix::sys::time::{TimeSpec, TimeVal, TimeValLike};
++use nix::unistd::chdir;
++
++#[cfg(not(any(target_os = "netbsd")))]
++use nix::Result;
++use tempfile;
++
++#[allow(unused_comparisons)]
++// uid and gid are signed on Windows, but not on other platforms. This function
++// allows warning free compiles on all platforms, and can be removed when
++// expression-level #[allow] is available.
++#[cfg(not(any(target_os = "netbsd")))]
++fn valid_uid_gid(stat: FileStat) -> bool {
++    // uid could be 0 for the `root` user. This quite possible when
++    // the tests are being run on a rooted Android device.
++    stat.st_uid >= 0 && stat.st_gid >= 0
++}
++
++#[cfg(not(any(target_os = "netbsd")))]
++fn assert_stat_results(stat_result: Result<FileStat>) {
++    let stats = stat_result.expect("stat call failed");
++    assert!(stats.st_dev > 0);      // must be positive integer, exact number machine dependent
++    assert!(stats.st_ino > 0);      // inode is positive integer, exact number machine dependent
++    assert!(stats.st_mode > 0);     // must be positive integer
++    assert!(stats.st_nlink == 1);   // there links created, must be 1
++    assert!(valid_uid_gid(stats));  // must be positive integers
++    assert!(stats.st_size == 0);    // size is 0 because we did not write anything to the file
++    assert!(stats.st_blksize > 0);  // must be positive integer, exact number machine dependent
++    assert!(stats.st_blocks <= 16);  // Up to 16 blocks can be allocated for a blank file
++}
++
++#[cfg(not(any(target_os = "netbsd")))]
++fn assert_lstat_results(stat_result: Result<FileStat>) {
++    let stats = stat_result.expect("stat call failed");
++    assert!(stats.st_dev > 0);      // must be positive integer, exact number machine dependent
++    assert!(stats.st_ino > 0);      // inode is positive integer, exact number machine dependent
++    assert!(stats.st_mode > 0);     // must be positive integer
++
++    // st_mode is c_uint (u32 on Android) while S_IFMT is mode_t
++    // (u16 on Android), and that will be a compile error.
++    // On other platforms they are the same (either both are u16 or u32).
++    assert!((stats.st_mode as usize) & (S_IFMT as usize) == S_IFLNK as usize); // should be a link
++    assert!(stats.st_nlink == 1);   // there links created, must be 1
++    assert!(valid_uid_gid(stats));  // must be positive integers
++    assert!(stats.st_size > 0);    // size is > 0 because it points to another file
++    assert!(stats.st_blksize > 0);  // must be positive integer, exact number machine dependent
++
++    // st_blocks depends on whether the machine's file system uses fast
++    // or slow symlinks, so just make sure it's not negative
++    // (Android's st_blocks is ulonglong which is always non-negative.)
++    assert!(stats.st_blocks >= 0);
++}
++
++#[test]
++#[cfg(not(any(target_os = "netbsd")))]
++fn test_stat_and_fstat() {
++    use nix::sys::stat::fstat;
++
++    let tempdir = tempfile::tempdir().unwrap();
++    let filename = tempdir.path().join("foo.txt");
++    let file = File::create(&filename).unwrap();
++
++    let stat_result = stat(&filename);
++    assert_stat_results(stat_result);
++
++    let fstat_result = fstat(file.as_raw_fd());
++    assert_stat_results(fstat_result);
++}
++
++#[test]
++#[cfg(not(any(target_os = "netbsd")))]
++fn test_fstatat() {
++    let tempdir = tempfile::tempdir().unwrap();
++    let filename = tempdir.path().join("foo.txt");
++    File::create(&filename).unwrap();
++    let dirfd = fcntl::open(tempdir.path(),
++                            fcntl::OFlag::empty(),
++                            stat::Mode::empty());
++
++    let result = stat::fstatat(dirfd.unwrap(),
++                               &filename,
++                               fcntl::AtFlags::empty());
++    assert_stat_results(result);
++}
++
++#[test]
++#[cfg(not(any(target_os = "netbsd")))]
++fn test_stat_fstat_lstat() {
++    use nix::sys::stat::{fstat, lstat};
++
++    let tempdir = tempfile::tempdir().unwrap();
++    let filename = tempdir.path().join("bar.txt");
++    let linkname = tempdir.path().join("barlink");
++
++    File::create(&filename).unwrap();
++    symlink("bar.txt", &linkname).unwrap();
++    let link = File::open(&linkname).unwrap();
++
++    // should be the same result as calling stat,
++    // since it's a regular file
++    let stat_result = stat(&filename);
++    assert_stat_results(stat_result);
++
++    let lstat_result = lstat(&linkname);
++    assert_lstat_results(lstat_result);
++
++    let fstat_result = fstat(link.as_raw_fd());
++    assert_stat_results(fstat_result);
++}
++
++#[test]
++fn test_fchmod() {
++    let tempdir = tempfile::tempdir().unwrap();
++    let filename = tempdir.path().join("foo.txt");
++    let file = File::create(&filename).unwrap();
++
++    let mut mode1 = Mode::empty();
++    mode1.insert(Mode::S_IRUSR);
++    mode1.insert(Mode::S_IWUSR);
++    fchmod(file.as_raw_fd(), mode1).unwrap();
++
++    let file_stat1 = stat(&filename).unwrap();
++    assert_eq!(file_stat1.st_mode & 0o7777, mode1.bits());
++
++    let mut mode2 = Mode::empty();
++    mode2.insert(Mode::S_IROTH);
++    fchmod(file.as_raw_fd(), mode2).unwrap();
++
++    let file_stat2 = stat(&filename).unwrap();
++    assert_eq!(file_stat2.st_mode & 0o7777, mode2.bits());
++}
++
++#[test]
++fn test_fchmodat() {
++    let _dr = ::DirRestore::new();
++    let tempdir = tempfile::tempdir().unwrap();
++    let filename = "foo.txt";
++    let fullpath = tempdir.path().join(filename);
++    File::create(&fullpath).unwrap();
++
++    let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++
++    let mut mode1 = Mode::empty();
++    mode1.insert(Mode::S_IRUSR);
++    mode1.insert(Mode::S_IWUSR);
++    fchmodat(Some(dirfd), filename, mode1, FchmodatFlags::FollowSymlink).unwrap();
++
++    let file_stat1 = stat(&fullpath).unwrap();
++    assert_eq!(file_stat1.st_mode & 0o7777, mode1.bits());
++
++    chdir(tempdir.path()).unwrap();
++
++    let mut mode2 = Mode::empty();
++    mode2.insert(Mode::S_IROTH);
++    fchmodat(None, filename, mode2, FchmodatFlags::FollowSymlink).unwrap();
++
++    let file_stat2 = stat(&fullpath).unwrap();
++    assert_eq!(file_stat2.st_mode & 0o7777, mode2.bits());
++}
++
++/// Asserts that the atime and mtime in a file's metadata match expected values.
++///
++/// The atime and mtime are expressed with a resolution of seconds because some file systems
++/// (like macOS's HFS+) do not have higher granularity.
++fn assert_times_eq(exp_atime_sec: u64, exp_mtime_sec: u64, attr: &fs::Metadata) {
++    assert_eq!(
++        Duration::new(exp_atime_sec, 0),
++        attr.accessed().unwrap().duration_since(UNIX_EPOCH).unwrap());
++    assert_eq!(
++        Duration::new(exp_mtime_sec, 0),
++        attr.modified().unwrap().duration_since(UNIX_EPOCH).unwrap());
++}
++
++#[test]
++fn test_utimes() {
++    let tempdir = tempfile::tempdir().unwrap();
++    let fullpath = tempdir.path().join("file");
++    drop(File::create(&fullpath).unwrap());
++
++    utimes(&fullpath, &TimeVal::seconds(9990), &TimeVal::seconds(5550)).unwrap();
++    assert_times_eq(9990, 5550, &fs::metadata(&fullpath).unwrap());
++}
++
++#[test]
++#[cfg(any(target_os = "linux",
++          target_os = "haiku",
++          target_os = "ios",
++          target_os = "macos",
++          target_os = "freebsd",
++          target_os = "netbsd"))]
++fn test_lutimes() {
++    let tempdir = tempfile::tempdir().unwrap();
++    let target = tempdir.path().join("target");
++    let fullpath = tempdir.path().join("symlink");
++    drop(File::create(&target).unwrap());
++    symlink(&target, &fullpath).unwrap();
++
++    let exp_target_metadata = fs::symlink_metadata(&target).unwrap();
++    lutimes(&fullpath, &TimeVal::seconds(4560), &TimeVal::seconds(1230)).unwrap();
++    assert_times_eq(4560, 1230, &fs::symlink_metadata(&fullpath).unwrap());
++
++    let target_metadata = fs::symlink_metadata(&target).unwrap();
++    assert_eq!(exp_target_metadata.accessed().unwrap(), target_metadata.accessed().unwrap(),
++               "atime of symlink target was unexpectedly modified");
++    assert_eq!(exp_target_metadata.modified().unwrap(), target_metadata.modified().unwrap(),
++               "mtime of symlink target was unexpectedly modified");
++}
++
++#[test]
++fn test_futimens() {
++    let tempdir = tempfile::tempdir().unwrap();
++    let fullpath = tempdir.path().join("file");
++    drop(File::create(&fullpath).unwrap());
++
++    let fd = fcntl::open(&fullpath, fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++
++    futimens(fd, &TimeSpec::seconds(10), &TimeSpec::seconds(20)).unwrap();
++    assert_times_eq(10, 20, &fs::metadata(&fullpath).unwrap());
++}
++
++#[test]
++fn test_utimensat() {
++    let _dr = ::DirRestore::new();
++    let tempdir = tempfile::tempdir().unwrap();
++    let filename = "foo.txt";
++    let fullpath = tempdir.path().join(filename);
++    drop(File::create(&fullpath).unwrap());
++
++    let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++
++    utimensat(Some(dirfd), filename, &TimeSpec::seconds(12345), &TimeSpec::seconds(678),
++              UtimensatFlags::FollowSymlink).unwrap();
++    assert_times_eq(12345, 678, &fs::metadata(&fullpath).unwrap());
++
++    chdir(tempdir.path()).unwrap();
++
++    utimensat(None, filename, &TimeSpec::seconds(500), &TimeSpec::seconds(800),
++              UtimensatFlags::FollowSymlink).unwrap();
++    assert_times_eq(500, 800, &fs::metadata(&fullpath).unwrap());
++}
++
++#[test]
++fn test_mkdirat_success_path() {
++    let tempdir = tempfile::tempdir().unwrap();
++    let filename = "example_subdir";
++    let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++    assert!((mkdirat(dirfd, filename, Mode::S_IRWXU)).is_ok());
++    assert!(Path::exists(&tempdir.path().join(filename)));
++}
++
++#[test]
++fn test_mkdirat_success_mode() {
++    let expected_bits = stat::SFlag::S_IFDIR.bits() | stat::Mode::S_IRWXU.bits();
++    let tempdir = tempfile::tempdir().unwrap();
++    let filename = "example_subdir";
++    let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++    assert!((mkdirat(dirfd, filename, Mode::S_IRWXU)).is_ok());
++    let permissions = fs::metadata(tempdir.path().join(filename)).unwrap().permissions();
++    let mode = permissions.mode();
++    assert_eq!(mode as mode_t, expected_bits)
++}
++
++#[test]
++fn test_mkdirat_fail() {
++    let tempdir = tempfile::tempdir().unwrap();
++    let not_dir_filename= "example_not_dir";
++    let filename = "example_subdir_dir";
++    let dirfd = fcntl::open(&tempdir.path().join(not_dir_filename), fcntl::OFlag::O_CREAT,
++                            stat::Mode::empty()).unwrap();
++    let result = mkdirat(dirfd, filename, Mode::S_IRWXU).unwrap_err();
++    assert_eq!(result, Error::Sys(Errno::ENOTDIR));
++}
+diff --git a/third_party/rust/nix-0.15.0/test/test_unistd.rs b/third_party/rust/nix-0.15.0/test/test_unistd.rs
+new file mode 100644
+index 0000000000000..46196dec7ccce
+--- /dev/null
++++ b/third_party/rust/nix-0.15.0/test/test_unistd.rs
+@@ -0,0 +1,669 @@
++use nix::fcntl::{self, fcntl, FcntlArg, FdFlag, open, OFlag, readlink};
++use nix::unistd::*;
++use nix::unistd::ForkResult::*;
++use nix::sys::signal::{SaFlags, SigAction, SigHandler, SigSet, Signal, sigaction};
++use nix::sys::wait::*;
++use nix::sys::stat::{self, Mode, SFlag};
++use nix::errno::Errno;
++use nix::Error;
++use std::{env, iter};
++use std::ffi::CString;
++use std::fs::{self, DirBuilder, File};
++use std::io::Write;
++use std::os::unix::prelude::*;
++use tempfile::{self, tempfile};
++use libc::{self, _exit, off_t};
++
++#[test]
++#[cfg(not(any(target_os = "netbsd")))]
++fn test_fork_and_waitpid() {
++    let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++
++    // Safe: Child only calls `_exit`, which is signal-safe
++    match fork().expect("Error: Fork Failed") {
++        Child => unsafe { _exit(0) },
++        Parent { child } => {
++            // assert that child was created and pid > 0
++            let child_raw: ::libc::pid_t = child.into();
++            assert!(child_raw > 0);
++            let wait_status = waitpid(child, None);
++            match wait_status {
++                // assert that waitpid returned correct status and the pid is the one of the child
++                Ok(WaitStatus::Exited(pid_t, _)) =>  assert!(pid_t == child),
++
++                // panic, must never happen
++                s @ Ok(_) => panic!("Child exited {:?}, should never happen", s),
++
++                // panic, waitpid should never fail
++                Err(s) => panic!("Error: waitpid returned Err({:?}", s)
++            }
++
++        },
++    }
++}
++
++#[test]
++fn test_wait() {
++    // Grab FORK_MTX so wait doesn't reap a different test's child process
++    let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++
++    // Safe: Child only calls `_exit`, which is signal-safe
++    match fork().expect("Error: Fork Failed") {
++        Child => unsafe { _exit(0) },
++        Parent { child } => {
++            let wait_status = wait();
++
++            // just assert that (any) one child returns with WaitStatus::Exited
++            assert_eq!(wait_status, Ok(WaitStatus::Exited(child, 0)));
++        },
++    }
++}
++
++#[test]
++fn test_mkstemp() {
++    let mut path = env::temp_dir();
++    path.push("nix_tempfile.XXXXXX");
++
++    let result = mkstemp(&path);
++    match result {
++        Ok((fd, path)) => {
++            close(fd).unwrap();
++            unlink(path.as_path()).unwrap();
++        },
++        Err(e) => panic!("mkstemp failed: {}", e)
++    }
++}
++
++#[test]
++fn test_mkstemp_directory() {
++    // mkstemp should fail if a directory is given
++    assert!(mkstemp(&env::temp_dir()).is_err());
++}
++
++#[test]
++fn test_mkfifo() {
++    let tempdir = tempfile::tempdir().unwrap();
++    let mkfifo_fifo = tempdir.path().join("mkfifo_fifo");
++
++    mkfifo(&mkfifo_fifo, Mode::S_IRUSR).unwrap();
++
++    let stats = stat::stat(&mkfifo_fifo).unwrap();
++    let typ = stat::SFlag::from_bits_truncate(stats.st_mode);
++    assert!(typ == SFlag::S_IFIFO);
++}
++
++#[test]
++fn test_mkfifo_directory() {
++    // mkfifo should fail if a directory is given
++    assert!(mkfifo(&env::temp_dir(), Mode::S_IRUSR).is_err());
++}
++
++#[test]
++fn test_getpid() {
++    let pid: ::libc::pid_t = getpid().into();
++    let ppid: ::libc::pid_t = getppid().into();
++    assert!(pid > 0);
++    assert!(ppid > 0);
++}
++
++#[test]
++fn test_getsid() {
++    let none_sid: ::libc::pid_t = getsid(None).unwrap().into();
++    let pid_sid: ::libc::pid_t = getsid(Some(getpid())).unwrap().into();
++    assert!(none_sid > 0);
++    assert!(none_sid == pid_sid);
++}
++
++#[cfg(any(target_os = "linux", target_os = "android"))]
++mod linux_android {
++    use nix::unistd::gettid;
++
++    #[test]
++    fn test_gettid() {
++        let tid: ::libc::pid_t = gettid().into();
++        assert!(tid > 0);
++    }
++}
++
++#[test]
++// `getgroups()` and `setgroups()` do not behave as expected on Apple platforms
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++fn test_setgroups() {
++    // Skip this test when not run as root as `setgroups()` requires root.
++    skip_if_not_root!("test_setgroups");
++
++    let _m = ::GROUPS_MTX.lock().expect("Mutex got poisoned by another test");
++
++    // Save the existing groups
++    let old_groups = getgroups().unwrap();
++
++    // Set some new made up groups
++    let groups = [Gid::from_raw(123), Gid::from_raw(456)];
++    setgroups(&groups).unwrap();
++
++    let new_groups = getgroups().unwrap();
++    assert_eq!(new_groups, groups);
++
++    // Revert back to the old groups
++    setgroups(&old_groups).unwrap();
++}
++
++#[test]
++// `getgroups()` and `setgroups()` do not behave as expected on Apple platforms
++#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++fn test_initgroups() {
++    // Skip this test when not run as root as `initgroups()` and `setgroups()`
++    // require root.
++    skip_if_not_root!("test_initgroups");
++
++    let _m = ::GROUPS_MTX.lock().expect("Mutex got poisoned by another test");
++
++    // Save the existing groups
++    let old_groups = getgroups().unwrap();
++
++    // It doesn't matter if the root user is not called "root" or if a user
++    // called "root" doesn't exist. We are just checking that the extra,
++    // made-up group, `123`, is set.
++    // FIXME: Test the other half of initgroups' functionality: whether the
++    // groups that the user belongs to are also set.
++    let user = CString::new("root").unwrap();
++    let group = Gid::from_raw(123);
++    let group_list = getgrouplist(&user, group).unwrap();
++    assert!(group_list.contains(&group));
++
++    initgroups(&user, group).unwrap();
++
++    let new_groups = getgroups().unwrap();
++    assert_eq!(new_groups, group_list);
++
++    // Revert back to the old groups
++    setgroups(&old_groups).unwrap();
++}
++
++macro_rules! execve_test_factory(
++    ($test_name:ident, $syscall:ident, $exe: expr $(, $pathname:expr, $flags:expr)*) => (
++    #[test]
++    fn $test_name() {
++        let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++        // The `exec`d process will write to `writer`, and we'll read that
++        // data from `reader`.
++        let (reader, writer) = pipe().unwrap();
++
++        // Safe: Child calls `exit`, `dup`, `close` and the provided `exec*` family function.
++        // NOTE: Technically, this makes the macro unsafe to use because you could pass anything.
++        //       The tests make sure not to do that, though.
++        match fork().unwrap() {
++            Child => {
++                // Close stdout.
++                close(1).unwrap();
++                // Make `writer` be the stdout of the new process.
++                dup(writer).unwrap();
++                // exec!
++                $syscall(
++                    $exe,
++                    $(&CString::new($pathname).unwrap(), )*
++                    &[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()]
++                    $(, $flags)*).unwrap();
++            },
++            Parent { child } => {
++                // Wait for the child to exit.
++                waitpid(child, None).unwrap();
++                // Read 1024 bytes.
++                let mut buf = [0u8; 1024];
++                read(reader, &mut buf).unwrap();
++                // It should contain the things we printed using `/bin/sh`.
++                let string = String::from_utf8_lossy(&buf);
++                assert!(string.contains("nix!!!"));
++                assert!(string.contains("foo=bar"));
++                assert!(string.contains("baz=quux"));
++            }
++        }
++    }
++    )
++);
++
++cfg_if!{
++    if #[cfg(target_os = "android")] {
++        execve_test_factory!(test_execve, execve, &CString::new("/system/bin/sh").unwrap());
++        execve_test_factory!(test_fexecve, fexecve, File::open("/system/bin/sh").unwrap().into_raw_fd());
++    } else if #[cfg(any(target_os = "freebsd",
++                        target_os = "linux"))] {
++        execve_test_factory!(test_execve, execve, &CString::new("/bin/sh").unwrap());
++        execve_test_factory!(test_fexecve, fexecve, File::open("/bin/sh").unwrap().into_raw_fd());
++    } else if #[cfg(any(target_os = "dragonfly",
++                        target_os = "ios",
++                        target_os = "macos",
++                        target_os = "netbsd",
++                        target_os = "openbsd"))] {
++        execve_test_factory!(test_execve, execve, &CString::new("/bin/sh").unwrap());
++        // No fexecve() on DragonFly, ios, macos, NetBSD, OpenBSD.
++        //
++        // Note for NetBSD and OpenBSD: although rust-lang/libc includes it
++        // (under unix/bsd/netbsdlike/) fexecve is not currently implemented on
++        // NetBSD nor on OpenBSD.
++    }
++}
++
++#[cfg(any(target_os = "haiku", target_os = "linux", target_os = "openbsd"))]
++execve_test_factory!(test_execvpe, execvpe, &CString::new("sh").unwrap());
++
++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(),
++                             "", AtFlags::AT_EMPTY_PATH);
++        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(),
++                             "/system/bin/sh", AtFlags::empty());
++    } 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);
++        execve_test_factory!(test_execveat_relative, execveat, File::open("/bin/").unwrap().into_raw_fd(),
++                             "./sh", AtFlags::empty());
++        execve_test_factory!(test_execveat_absolute, execveat, File::open("/").unwrap().into_raw_fd(),
++                             "/bin/sh", AtFlags::empty());
++    }
++}
++
++#[test]
++fn test_fchdir() {
++    // fchdir changes the process's cwd
++    let _dr = ::DirRestore::new();
++
++    let tmpdir = tempfile::tempdir().unwrap();
++    let tmpdir_path = tmpdir.path().canonicalize().unwrap();
++    let tmpdir_fd = File::open(&tmpdir_path).unwrap().into_raw_fd();
++
++    assert!(fchdir(tmpdir_fd).is_ok());
++    assert_eq!(getcwd().unwrap(), tmpdir_path);
++
++    assert!(close(tmpdir_fd).is_ok());
++}
++
++#[test]
++fn test_getcwd() {
++    // chdir changes the process's cwd
++    let _dr = ::DirRestore::new();
++
++    let tmpdir = tempfile::tempdir().unwrap();
++    let tmpdir_path = tmpdir.path().canonicalize().unwrap();
++    assert!(chdir(&tmpdir_path).is_ok());
++    assert_eq!(getcwd().unwrap(), tmpdir_path);
++
++    // make path 500 chars longer so that buffer doubling in getcwd
++    // kicks in.  Note: One path cannot be longer than 255 bytes
++    // (NAME_MAX) whole path cannot be longer than PATH_MAX (usually
++    // 4096 on linux, 1024 on macos)
++    let mut inner_tmp_dir = tmpdir_path.to_path_buf();
++    for _ in 0..5 {
++        let newdir = iter::repeat("a").take(100).collect::<String>();
++        inner_tmp_dir.push(newdir);
++        assert!(mkdir(inner_tmp_dir.as_path(), Mode::S_IRWXU).is_ok());
++    }
++    assert!(chdir(inner_tmp_dir.as_path()).is_ok());
++    assert_eq!(getcwd().unwrap(), inner_tmp_dir.as_path());
++}
++
++#[test]
++fn test_chown() {
++    // Testing for anything other than our own UID/GID is hard.
++    let uid = Some(getuid());
++    let gid = Some(getgid());
++
++    let tempdir = tempfile::tempdir().unwrap();
++    let path = tempdir.path().join("file");
++    {
++        File::create(&path).unwrap();
++    }
++
++    chown(&path, uid, gid).unwrap();
++    chown(&path, uid, None).unwrap();
++    chown(&path, None, gid).unwrap();
++
++    fs::remove_file(&path).unwrap();
++    chown(&path, uid, gid).unwrap_err();
++}
++
++#[test]
++fn test_fchownat() {
++    let _dr = ::DirRestore::new();
++    // Testing for anything other than our own UID/GID is hard.
++    let uid = Some(getuid());
++    let gid = Some(getgid());
++
++    let tempdir = tempfile::tempdir().unwrap();
++    let path = tempdir.path().join("file");
++    {
++        File::create(&path).unwrap();
++    }
++
++    let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
++
++    fchownat(Some(dirfd), "file", uid, gid, FchownatFlags::FollowSymlink).unwrap();
++
++    chdir(tempdir.path()).unwrap();
++    fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap();
++
++    fs::remove_file(&path).unwrap();
++    fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap_err();
++}
++
++#[test]
++fn test_lseek() {
++    const CONTENTS: &[u8] = b"abcdef123456";
++    let mut tmp = tempfile().unwrap();
++    tmp.write_all(CONTENTS).unwrap();
++    let tmpfd = tmp.into_raw_fd();
++
++    let offset: off_t = 5;
++    lseek(tmpfd, offset, Whence::SeekSet).unwrap();
++
++    let mut buf = [0u8; 7];
++    ::read_exact(tmpfd, &mut buf);
++    assert_eq!(b"f123456", &buf);
++
++    close(tmpfd).unwrap();
++}
++
++#[cfg(any(target_os = "linux", target_os = "android"))]
++#[test]
++fn test_lseek64() {
++    const CONTENTS: &[u8] = b"abcdef123456";
++    let mut tmp = tempfile().unwrap();
++    tmp.write_all(CONTENTS).unwrap();
++    let tmpfd = tmp.into_raw_fd();
++
++    lseek64(tmpfd, 5, Whence::SeekSet).unwrap();
++
++    let mut buf = [0u8; 7];
++    ::read_exact(tmpfd, &mut buf);
++    assert_eq!(b"f123456", &buf);
++
++    close(tmpfd).unwrap();
++}
++
++cfg_if!{
++    if #[cfg(any(target_os = "android", target_os = "linux"))] {
++        macro_rules! require_acct{
++            () => {
++                require_capability!(CAP_SYS_PACCT);
++            }
++        }
++    } else if #[cfg(target_os = "freebsd")] {
++        macro_rules! require_acct{
++            () => {
++                skip_if_not_root!("test_acct");
++                skip_if_jailed!("test_acct");
++            }
++        }
++    } else {
++        macro_rules! require_acct{
++            () => {
++                skip_if_not_root!("test_acct");
++            }
++        }
++    }
++}
++
++#[test]
++fn test_acct() {
++    use tempfile::NamedTempFile;
++    use std::process::Command;
++    use std::{thread, time};
++
++    let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++    require_acct!();
++
++    let file = NamedTempFile::new().unwrap();
++    let path = file.path().to_str().unwrap();
++
++    acct::enable(path).unwrap();
++
++    loop {
++        Command::new("echo").arg("Hello world");
++        let len = fs::metadata(path).unwrap().len();
++        if len > 0 { break; }
++        thread::sleep(time::Duration::from_millis(10));
++    }
++    acct::disable().unwrap();
++}
++
++#[test]
++fn test_fpathconf_limited() {
++    let f = tempfile().unwrap();
++    // AFAIK, PATH_MAX is limited on all platforms, so it makes a good test
++    let path_max = fpathconf(f.as_raw_fd(), PathconfVar::PATH_MAX);
++    assert!(path_max.expect("fpathconf failed").expect("PATH_MAX is unlimited") > 0);
++}
++
++#[test]
++fn test_pathconf_limited() {
++    // AFAIK, PATH_MAX is limited on all platforms, so it makes a good test
++    let path_max = pathconf("/", PathconfVar::PATH_MAX);
++    assert!(path_max.expect("pathconf failed").expect("PATH_MAX is unlimited") > 0);
++}
++
++#[test]
++fn test_sysconf_limited() {
++    // AFAIK, OPEN_MAX is limited on all platforms, so it makes a good test
++    let open_max = sysconf(SysconfVar::OPEN_MAX);
++    assert!(open_max.expect("sysconf failed").expect("OPEN_MAX is unlimited") > 0);
++}
++
++#[cfg(target_os = "freebsd")]
++#[test]
++fn test_sysconf_unsupported() {
++    // I know of no sysconf variables that are unsupported everywhere, but
++    // _XOPEN_CRYPT is unsupported on FreeBSD 11.0, which is one of the platforms
++    // we test.
++    let open_max = sysconf(SysconfVar::_XOPEN_CRYPT);
++    assert!(open_max.expect("sysconf failed").is_none())
++}
++
++// Test that we can create a pair of pipes.  No need to verify that they pass
++// data; that's the domain of the OS, not nix.
++#[test]
++fn test_pipe() {
++    let (fd0, fd1) = pipe().unwrap();
++    let m0 = stat::SFlag::from_bits_truncate(stat::fstat(fd0).unwrap().st_mode);
++    // S_IFIFO means it's a pipe
++    assert_eq!(m0, SFlag::S_IFIFO);
++    let m1 = stat::SFlag::from_bits_truncate(stat::fstat(fd1).unwrap().st_mode);
++    assert_eq!(m1, SFlag::S_IFIFO);
++}
++
++// pipe2(2) is the same as pipe(2), except it allows setting some flags.  Check
++// that we can set a flag.
++#[test]
++fn test_pipe2() {
++    let (fd0, fd1) = pipe2(OFlag::O_CLOEXEC).unwrap();
++    let f0 = FdFlag::from_bits_truncate(fcntl(fd0, FcntlArg::F_GETFD).unwrap());
++    assert!(f0.contains(FdFlag::FD_CLOEXEC));
++    let f1 = FdFlag::from_bits_truncate(fcntl(fd1, FcntlArg::F_GETFD).unwrap());
++    assert!(f1.contains(FdFlag::FD_CLOEXEC));
++}
++
++#[test]
++fn test_truncate() {
++    let tempdir = tempfile::tempdir().unwrap();
++    let path = tempdir.path().join("file");
++
++    {
++        let mut tmp = File::create(&path).unwrap();
++        const CONTENTS: &[u8] = b"12345678";
++        tmp.write_all(CONTENTS).unwrap();
++    }
++
++    truncate(&path, 4).unwrap();
++
++    let metadata = fs::metadata(&path).unwrap();
++    assert_eq!(4, metadata.len());
++}
++
++#[test]
++fn test_ftruncate() {
++    let tempdir = tempfile::tempdir().unwrap();
++    let path = tempdir.path().join("file");
++
++    let tmpfd = {
++        let mut tmp = File::create(&path).unwrap();
++        const CONTENTS: &[u8] = b"12345678";
++        tmp.write_all(CONTENTS).unwrap();
++        tmp.into_raw_fd()
++    };
++
++    ftruncate(tmpfd, 2).unwrap();
++    close(tmpfd).unwrap();
++
++    let metadata = fs::metadata(&path).unwrap();
++    assert_eq!(2, metadata.len());
++}
++
++// Used in `test_alarm`.
++static mut ALARM_CALLED: bool = false;
++
++// Used in `test_alarm`.
++pub extern fn alarm_signal_handler(raw_signal: libc::c_int) {
++    assert_eq!(raw_signal, libc::SIGALRM, "unexpected signal: {}", raw_signal);
++    unsafe { ALARM_CALLED = true };
++}
++
++#[test]
++fn test_alarm() {
++    let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++
++    let handler = SigHandler::Handler(alarm_signal_handler);
++    let signal_action = SigAction::new(handler, SaFlags::SA_RESTART, SigSet::empty());
++    let old_handler = unsafe {
++        sigaction(Signal::SIGALRM, &signal_action)
++            .expect("unable to set signal handler for alarm")
++    };
++
++    // Set an alarm.
++    assert_eq!(alarm::set(60), None);
++
++    // Overwriting an alarm should return the old alarm.
++    assert_eq!(alarm::set(1), Some(60));
++
++    // 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");
++
++    // Reset the signal.
++    unsafe {
++        sigaction(Signal::SIGALRM, &old_handler)
++            .expect("unable to set signal handler for alarm");
++    }
++}
++
++#[test]
++fn test_canceling_alarm() {
++    let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++
++    assert_eq!(alarm::cancel(), None);
++
++    assert_eq!(alarm::set(60), None);
++    assert_eq!(alarm::cancel(), Some(60));
++}
++
++#[test]
++fn test_symlinkat() {
++    let mut buf = [0; 1024];
++    let tempdir = tempfile::tempdir().unwrap();
++
++    let target = tempdir.path().join("a");
++    let linkpath = tempdir.path().join("b");
++    symlinkat(&target, None, &linkpath).unwrap();
++    assert_eq!(
++        readlink(&linkpath, &mut buf).unwrap().to_str().unwrap(),
++        target.to_str().unwrap()
++    );
++
++    let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
++    let target = "c";
++    let linkpath = "d";
++    symlinkat(target, Some(dirfd), linkpath).unwrap();
++    assert_eq!(
++        readlink(&tempdir.path().join(linkpath), &mut buf)
++            .unwrap()
++            .to_str()
++            .unwrap(),
++        target
++    );
++}
++
++
++#[test]
++fn test_unlinkat_dir_noremovedir() {
++    let tempdir = tempfile::tempdir().unwrap();
++    let dirname = "foo_dir";
++    let dirpath = tempdir.path().join(dirname);
++
++    // Create dir
++    DirBuilder::new().recursive(true).create(&dirpath).unwrap();
++
++    // Get file descriptor for base directory
++    let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++
++    // Attempt unlink dir at relative path without proper flag
++    let err_result = unlinkat(Some(dirfd), dirname, UnlinkatFlags::NoRemoveDir).unwrap_err();
++    assert!(err_result == Error::Sys(Errno::EISDIR) || err_result == Error::Sys(Errno::EPERM));
++ }
++
++#[test]
++fn test_unlinkat_dir_removedir() {
++    let tempdir = tempfile::tempdir().unwrap();
++    let dirname = "foo_dir";
++    let dirpath = tempdir.path().join(dirname);
++
++    // Create dir
++    DirBuilder::new().recursive(true).create(&dirpath).unwrap();
++
++    // Get file descriptor for base directory
++    let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++
++    // Attempt unlink dir at relative path with proper flag
++    unlinkat(Some(dirfd), dirname, UnlinkatFlags::RemoveDir).unwrap();
++    assert!(!dirpath.exists());
++ }
++
++#[test]
++fn test_unlinkat_file() {
++    let tempdir = tempfile::tempdir().unwrap();
++    let filename = "foo.txt";
++    let filepath = tempdir.path().join(filename);
++
++    // Create file
++    File::create(&filepath).unwrap();
++
++    // Get file descriptor for base directory
++    let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++
++    // Attempt unlink file at relative path
++    unlinkat(Some(dirfd), filename, UnlinkatFlags::NoRemoveDir).unwrap();
++    assert!(!filepath.exists());
++ }
++
++#[test]
++fn test_access_not_existing() {
++    let tempdir = tempfile::tempdir().unwrap();
++    let dir = tempdir.path().join("does_not_exist.txt");
++    assert_eq!(access(&dir, AccessFlags::F_OK).err().unwrap().as_errno().unwrap(),
++               Errno::ENOENT);
++}
++
++#[test]
++fn test_access_file_exists() {
++    let tempdir = tempfile::tempdir().unwrap();
++    let path  = tempdir.path().join("does_exist.txt");
++    let _file = File::create(path.clone()).unwrap();
++    assert!(access(&path, AccessFlags::R_OK | AccessFlags::W_OK).is_ok());
++}
+diff --git a/third_party/rust/nix/.cargo-checksum.json b/third_party/rust/nix/.cargo-checksum.json
+index e5f2bc789185a..85adbc1eae931 100644
+--- a/third_party/rust/nix/.cargo-checksum.json
++++ b/third_party/rust/nix/.cargo-checksum.json
+@@ -1 +1 @@
+-{"files":{"CHANGELOG.md":"91af9fd5f2d9cdb9c8bb750e24b625742e95a6c74bcff419f3de70eb26578281","CONTRIBUTING.md":"a9101e3d1487170d691d5f062ff49a433c167582ac8984dd41a744be92652f74","CONVENTIONS.md":"e150ce43c1d188c392c1a3bf7f2e08e3cf84906705c7bef43f319037d29ea385","Cargo.toml":"af0cc0ae7ff4bf6c2e5b35fe062f54fe2d619f70ba67795f4f43a981420b5de0","LICENSE":"66e3ee1fa7f909ad3c612d556f2a0cdabcd809ad6e66f3b0605015ac64841b70","README.md":"80d71b9eaac7bf7f0d307372592ed1467f994291e6fad816a44f3c70e2887d0f","build.rs":"14c9c678c33f5894509da47f77d6a326b14aecb4190ce87a24cce98687ca63b2","src/dir.rs":"21e330cbe6594274335b94d9e9b6059f1fa8e53d2e5b5c697058c52ec6b3c5ff","src/errno.rs":"a009ccf18b45c0a4c9319c65b0dc5bc322d9ad43cfe462ec4661559f44162451","src/errno_dragonfly.c":"a857e47b114acb85fddcb252a610ab5734d225c26b7bedd7c35d7789d46c8526","src/fcntl.rs":"6ae2f7f01dd2568b82a4e57f86e02b1d63eec6c26111c5adb2ca5d78a2a99fe7","src/features.rs":"22ff626ff8287a07dd55bcfc63c9f518c19c56144e15f9b6f9e3bbdcda51c2a8","
 src/ifaddrs.rs":"9a93de176edcca4613e668b8ccc2c3e3b6b711aa2d8d94ccb0ba08694d1ef35f","src/kmod.rs":"4d8a695d3d761f351a39d654303a1bd168e74295b7d142b918737e355b24f34d","src/lib.rs":"fdd8049a79ffb92384c72f0a6b0bab717001ddfa9b01f2b33413c83f424f2ac8","src/macros.rs":"aec27fa0fd98900913fada926c9a4581cd28f2640e3a7b5480707f923c9200f8","src/mount.rs":"cdf5db8409017483132db9d7493b5d6cc96df5560d0fa5ad8f385aff72db10ca","src/mqueue.rs":"82af42b31381af73e7966f845d1ed93957f0b9976bf2da524b178fad15b2b08d","src/net/if_.rs":"f7e02076fcf3cadf3fdf141884c9bd2c468a7047ba60bc490f0057df802b53ce","src/net/mod.rs":"577f70170e53d4a6de1abb70bf8f1031ec3e65c0e63ef5fcf05c907125e7ac17","src/poll.rs":"7305e250066cd1a7318cd239ed3db787937ee98426fe9289cf00fa874d76b6c7","src/pty.rs":"6b965b586579933af47d4efef4c82c391b927037eaa08d8c83fc974ef17fc7c8","src/sched.rs":"f9b214fa60006b5450ffb3589a55ec59c3694bd49597c65c38ac813fcd96c7dd","src/sys/aio.rs":"a1ba629258b3ce1268e5fe8e5b41dce3581f77d415dc5e2455c1f82f26dd3085","src/sys/e
 poll.rs":"f0b539e0645569657f2142db91a38c94ebe1925f44852d64c61c818758dbbf0b","src/sys/event.rs":"ef8bc02a08d9ce7924c87f8f891fa051587b195a36913712fe85237a2fe0685b","src/sys/eventfd.rs":"08008cf3dc64c2216847c02c0dd8d7189cf08edbaafe35ba2c57c053fde09ef4","src/sys/inotify.rs":"687c8417d737939aa93f805d6003afc4f84f50828b1bd9429ef5d00bef0e0955","src/sys/ioctl/bsd.rs":"56ca6ecf5f7cfb566f4f3ba589fcc778f747a517dd45e13780981922e6215344","src/sys/ioctl/linux.rs":"6cfbdff4dbfa1a3782acdedebe89ffa9f000fdfc4ab68cb46f52890ebc1c6f2d","src/sys/ioctl/mod.rs":"20bc3cf1fcbbc7c31e4d507baa4e576a793ea42fb33618d2e7afeda730c4324f","src/sys/memfd.rs":"11cd93c867fdbdbc9588cecb94268691de42b2ef2a38fe33525be7c7f60c85d5","src/sys/mman.rs":"f77d28611a7ff3bf62784a3c4f26d7d79969395b1d9bbc6ff15e734f52dc404f","src/sys/mod.rs":"f39a08c72e37638c7cecfb9c087e0a41e2b69409aa545b0ef7bbd59c0a063ee2","src/sys/pthread.rs":"cfa9ccd6f3b86c0c3fe012773c9c82a7813b298c2f20f8ab629781db627ce56b","src/sys/ptrace/bsd.rs":"8a7eacfc172b55763ae
 32109bf9b252669ba68b72cd5122f7504eb35c0c08345","src/sys/ptrace/linux.rs":"f09b45148004f4b28d8503c397a8d112d31046c98e68335bf4e89425d5b33f07","src/sys/ptrace/mod.rs":"671a6ccac955e75d5998f7e53ffc45ed4c7b6522a0f24a0937d60141f692dd39","src/sys/quota.rs":"7eb8e797466b506f6ed882f18eda92c4639cf43d9384a19bc39cd1bf982989c9","src/sys/reboot.rs":"fde9da27c2928f7026231430fa14fec2058df4e49a0aeda2a237a60524f11241","src/sys/select.rs":"57d6c4403d1bf788bd52ab6f03cfc16a189d31b6bfb338b135cb775fe369121f","src/sys/sendfile.rs":"ea386e83baf9b5b23488aca26635aacdc92f2bfe238e4399a7380bd0331e0ef7","src/sys/signal.rs":"9216cdd609b4dfb9c2e559c411be6b7c722f7ddd8024682c0895a32126b488aa","src/sys/signalfd.rs":"bfcfce619bf199e50f9cc80a3eb778d48474a015cfdafc64a0c3517373a225a9","src/sys/socket/addr.rs":"8b297ce13cd8ad200b3e764888c26ceb582ee505385d1e172440de94ade99644","src/sys/socket/mod.rs":"e0353f04f3d098a8bf5e2aae431645897b96e0889fb76537dc0330159c6f233d","src/sys/socket/sockopt.rs":"c663505d6a7a7ae9d76e03fbc17e5
 3d308ea6b1eae92212812e1d76b2bf2916f","src/sys/stat.rs":"c4807048f86be67026756737cf81f448ec23c2a4745776cb40f40b533a88e0c8","src/sys/statfs.rs":"d2b72069f20aa7782ce5de4ec2d00c76a82a92376c2066bbb270cdac2167719e","src/sys/statvfs.rs":"2d328cf525ba04ab1e1351128624a7df7d0c55ea91fda6c8d620d13710d61606","src/sys/sysinfo.rs":"0c05244655aa9e6dff5138392c5c1ae97630d35bae0e5510d7f51a75c31fd425","src/sys/termios.rs":"a2e99afdfc3526641a2cb82b57bfd0a25a362fb9be5ad37ff9f11acaeb0b9439","src/sys/time.rs":"8a1224b9262026086af698630aedbed21b45d661fbd045fc6c6af41a16a23374","src/sys/uio.rs":"60a974275ff8c485ea183bdd6f7e25894e6f2360a5bfb25442391a825a3b9b8c","src/sys/utsname.rs":"c977a1aec6e051c72b27506395e942abab9cbd9523e6d345ea66dc10875ee87d","src/sys/wait.rs":"30b14a8f518d031805cae6c6ff644116f162d8c8a75fddcfce4479d8d55fd1c0","src/ucontext.rs":"075560ec08a362881534211f8c6b78844886d6b767c2f7067174600e38ed3f63","src/unistd.rs":"82308ec31b6293b55f86fafd04e976a41127fedebb8f158abd1399c7399af947","test/sys/mod.
 rs":"e0821cbc289ad952f17229609c7de4282cca1e44cd13e1a7494a6378ecbc12f8","test/sys/test_aio.rs":"b2544bfb321ca7fbed276ee637c769fb438156d14666cdc1e1d547b3514a44e3","test/sys/test_aio_drop.rs":"30dd1d238269d00381fa50f6d3cb2b13794b7cceb9f6455f3878fcbffa9aa62d","test/sys/test_epoll.rs":"35093d0cb1096a934dfc4f6efc737eadc4bdc2e2134d2a879061374a51b10c97","test/sys/test_inotify.rs":"a4f804bcf414b6635d9863c8534769a609009c451c3476cc839cdc30c439b3b1","test/sys/test_ioctl.rs":"eea690ed386da0a666df5eb23a417421fddb99dc8e39556f63b30969bb6cf779","test/sys/test_lio_listio_resubmit.rs":"203a583313542593148f375b087ae30620222a745680173fa98fc448d1e5ae7f","test/sys/test_pthread.rs":"3890e5ecbf2082e0d05d102cc9cec6e76ede3c15f250d104e3483b1c1c3400b1","test/sys/test_ptrace.rs":"4e8d5dff5fe6bc56e4ae53bdfd10f5e8ea567d8099576d1c690cf7a6b2bc955f","test/sys/test_select.rs":"bdb20211fc6ec1e3f186337eac51e08757acb6901d307d67c71bf9011f0d54bd","test/sys/test_signal.rs":"84ae63c2baa49eebeabe5bbd347b9c5417e14ba97f342719d7
 53dc1c1c768d60","test/sys/test_signalfd.rs":"71b5d6d782283f6db64ca90f7fb06617faec71091d59d2587e41bbc9d8c43d5c","test/sys/test_socket.rs":"09a7ef0322e07b4579893e0307a7c4f81fbbc653d005b827a519c33a33e185ce","test/sys/test_sockopt.rs":"b3d386c8279f86bf9439c772317bafcdba5630fa806c8319e87ddac0ccfa3a03","test/sys/test_sysinfo.rs":"1e1bea9130fe38ccb07cd0ad7334c7be1e45efc33f7656a5973f8cad7126f225","test/sys/test_termios.rs":"fa4be3ade859b527bf33408f85a6f57b127917cf5f2afb662d09f6019d07913a","test/sys/test_uio.rs":"9da234e3bd5003fd200cc37c4a5be147ecda1a7670feb1d505f23d646d3e1c57","test/sys/test_wait.rs":"e6c5147e213daa93892cd828f53214995d2e019ff2372cc48d85ce9b93d26ec9","test/test.rs":"e6307f82a39426a949b8e925a2df4a62e31c0e43081d7a33d23759bdfeeece1f","test/test_dir.rs":"5d137a62f11d1a4993b4bb35dccc38a4c4416b7da374887f2335a9895b4fdee4","test/test_fcntl.rs":"730e64e99dc867ba5af7cc4ca83a4489c8b96b1a52f8937bcc666d673af27002","test/test_kmod/hello_mod/Makefile":"0219f7bce0603f97d997fb377ca071966c903
 33ecc665e78a54dfeb97a9c811b","test/test_kmod/hello_mod/hello.c":"bcac6b19c5bd807e1f3878c15e426acc85785a8ade9840c3bb4d068635c9188c","test/test_kmod/mod.rs":"f4754f028402a8ba788c87686288424cd3784e77c7eb5d96682ef491b1dd5262","test/test_mount.rs":"78ddc657f5098360c764fffa3a7d844503e4b6b65b44bfd42d9aa9045b415cb6","test/test_mq.rs":"5806f8825e91edc79dd0e2bc81d8be3ba094c2de6c0b2ac0268221ae2ad22701","test/test_net.rs":"ec6d580b87292519d514b0236bdd5abdd576fcf4835cfe49ed1ddb47c5f1aea3","test/test_nix_path.rs":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","test/test_poll.rs":"46c71ee988fe1b85561ea0530d099750be8c1b8f95ab6e845c8a9f46f16f060c","test/test_pty.rs":"be04f99904fa47b60400c2bd156a388b73df4b9aec2eebf13df7dcdfc9aacf45","test/test_ptymaster_drop.rs":"5cfbbb79551c205ab510c2d4ef497bf937ceac9151fbe2f2e543d6515e406990","test/test_sendfile.rs":"e0cbabbd34052ccaa03d6555d5631686aa076728f6378ee90f7ecec68f891144","test/test_stat.rs":"1dc420d3119bf4d863a7ae0ba63efa7f1416f6e46e4
 100ea161003fe1c3f66ba","test/test_unistd.rs":"0325c998acca1e826e9e2b3d351d55ab9723a6cb2ca2072245978e7f5a9acee8"},"package":"3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229"}
+\ No newline at end of file
++{"files":{"CHANGELOG.md":"9294216482039acf0dd5911548feaaf04d410298fc5cd3df450d8d36c914756e","CONTRIBUTING.md":"7da4f8c2ff8e06850bdd9ebc0a3552419fd21d2c6bb0c6f0719566e263b0a1b9","CONVENTIONS.md":"df0d4fe9fe65af0bfa4723dc7b641d5130087259799e6b404ad63884f79031cb","Cargo.toml":"03e8c7ae8afb88e9d698712e2428d19a367c19079e994a170cb16dca985cc48d","LICENSE":"66e3ee1fa7f909ad3c612d556f2a0cdabcd809ad6e66f3b0605015ac64841b70","README.md":"d7a8568ffb72d76acc2812d8f545ad71b24a7c1301d2a258f49057fcaded0b9f","src/dir.rs":"52170e8bfc8c4bc1996db2f5cd5a2aace71beac59e4a0e7c1817fdecbf8bd6a7","src/env.rs":"bc52e80d3fa6c5388e3e23767d214a72f88d2927c5604246016c4cf978bbbeb7","src/errno.rs":"1aab33e5dcab9c6f83e48e452f361840645ce6a434bc13bd8ab9abb0e0ef25c3","src/fcntl.rs":"7f3f95baad70ceb1231b8a647988a8e54292d84176820eb6a9f89d40f309c3a6","src/features.rs":"2cb080da3f26eca2d2e18282a41afec921426423a6354a50b840cf20f3f153f6","src/ifaddrs.rs":"4f19ed3b15f5059c2859958c6aa313d6fa75703e68f8608359ef8e0089508ed3","src/k
 mod.rs":"873bec7f32e30a552a4fd86d5f884c2b3a0cd73012121dfe1587b508475beb0a","src/lib.rs":"ae1a16e142c47afc3f52a07a2afb2fc013cfd427df955aa42e4bd372c77c49d5","src/macros.rs":"7c6c81441c967d73a75a975bb660ae48efde22c6f5ae2705c62a8db446ce0d39","src/mount.rs":"cde7c59b79a8e535c4d8c57c53d7825384b110be244803b1f895d5a3b97bc72f","src/mqueue.rs":"3520495f6a881a7239fba19e90234f7fc9df6729b6bc150bd2e6664b7c98d6a1","src/net/if_.rs":"928066a6ec473ce565e2323858ff64e179e4b81b80768d830dd29008f2fafb7f","src/net/mod.rs":"577f70170e53d4a6de1abb70bf8f1031ec3e65c0e63ef5fcf05c907125e7ac17","src/poll.rs":"ba635fbed688a165279a9851269310220befd211c8fcf5761d1a62dab39ba52b","src/pty.rs":"7a73ba21b2ec8910f7932e456d2fb097a0553c5fe07717238c58455e3de7b275","src/sched.rs":"2bdb5ce449bc093a8eecdd8964e5d05feee3e7b804e4271e40d674178295df79","src/sys/aio.rs":"bbcc1d8639a9c89c66c00357353dde94d0f48b516b4354ab3d3dcfc16a2e0b56","src/sys/epoll.rs":"a3ace2282e77989e9b927dcdca8ad2070d4fb7710398af0763ea6eb26d431968","src/sys/even
 t.rs":"075e84e5a5d1fd922fbcac8c01c8e7cd7f1a1c1f8f60ede8f7ebc5fe6d5e76ac","src/sys/eventfd.rs":"b5301029e95f77f280cc169bb8aa247352efbb600c749f26e2fffa0474c872bb","src/sys/inotify.rs":"114be3860c9daaee1c781df90b63abb87cd82d677c4470b359bbf0787a25d302","src/sys/ioctl/bsd.rs":"853b50c3539dc4a1284c847f2689fde3dbed5dca7a8599db36193048e030296a","src/sys/ioctl/linux.rs":"642b25d3997518815dea454fa976e9067ad5fe4ed75622e7540e3f0d0c7d320a","src/sys/ioctl/mod.rs":"dd3435e44c42f55a600e40599038bebc7417934dade00113ef0f3b6318bf54de","src/sys/memfd.rs":"35dba6c3eeb4f74edbf86530ba1696d9251495b82b814a36b76e6d2b26490e3c","src/sys/mman.rs":"bdca4a151dc31d27c7435e30a5030ad2edef9dd3ac69a33363454cada8466ca3","src/sys/mod.rs":"b8d7d9e3cb331f1d972699cfbaa54fff34a9f26eaba38b8ee49e84bfeee22bd3","src/sys/personality.rs":"2019e58aa69c5ad68ae060e1b9a399138a2e4742f37a868e2681588963ca8acf","src/sys/pthread.rs":"cfa9ccd6f3b86c0c3fe012773c9c82a7813b298c2f20f8ab629781db627ce56b","src/sys/ptrace/bsd.rs":"feced79575c5dbea
 f0a0877ba888761675310b277f477acee820c785e132dbe9","src/sys/ptrace/linux.rs":"34524ad4911d2ef7ec0e21a49e479d6fd91d4ef5c660e0b7e2afa4878b27367a","src/sys/ptrace/mod.rs":"671a6ccac955e75d5998f7e53ffc45ed4c7b6522a0f24a0937d60141f692dd39","src/sys/quota.rs":"4ceb895896bbd0bb67ce98e91dec3bd40c9a7d5936abbe13b74691c6afa07f9f","src/sys/reboot.rs":"1fd26955bc095bd4f8804c850183f527560803cbceaf345c3760c8f32fe1224f","src/sys/select.rs":"02226a733d160701f07d27384f87bf21032f3cc4d5a6214dc61e398dd1606b60","src/sys/sendfile.rs":"110955788e3f5f36a7e563c334c6fe400edfb93d6cb2fdce6b8a79d2e892f8ce","src/sys/signal.rs":"53232ef1165272d109173fbba769cde77f3446050dbdaf36e56c4c0fde084348","src/sys/signalfd.rs":"37704804eb75571d03bbc1c99bd90846ae50ce361cc9998777744f8265d51074","src/sys/socket/addr.rs":"0513e0fbe57c19f8f9538e31074a4ed50c443fd45dd66ce1fa56db2dee46b371","src/sys/socket/mod.rs":"7d0d0b2da45d45493c494ad8669f53577439510914777b03febb6d2f18dcc787","src/sys/socket/sockopt.rs":"42b335e7a2e2b8cf1605065244
 90bb685bd2488ebff65921aa10f60363ffda7b","src/sys/stat.rs":"a969ae88221a50c89d54f97987d108d3c017339d7eedd66ac7218463d2bb07db","src/sys/statfs.rs":"6bd23f941107dc79ec34dc50516ff5eb18d9fad108ad976796669505692c1582","src/sys/statvfs.rs":"09a7268f3f6f321961e4f25943236fe103fe8c7661ea841f4e71014fda0d8952","src/sys/sysinfo.rs":"1aa6f402bc10689c5dd7ad454ecb60834e2b065dddbd3d87d1daecf88cb2b3ee","src/sys/termios.rs":"c3c310cdec9c7c80e7b11ada25d3dc87c0d0fc6c30fcda8f94edab1d27132300","src/sys/time.rs":"cc955b6b6647ca1db33ac076780ca6c984200e3cc47df5d836b1528489cdef70","src/sys/timerfd.rs":"51443f37b1dd4b03f16e1b569945f0ae715db4028f69e3ddd6c311db00e67ab3","src/sys/uio.rs":"a25dd7a84135ea50a671a7a06a8989dc9d53d3e755d36cef9f37cdc79a123d9d","src/sys/utsname.rs":"9509a092c837d1700f9f4ac30e4568e5b9b63ad8925a56cd8ad7add05d0ac452","src/sys/wait.rs":"ab18e66acaf161750394d802409ee8c95707dbd68d2fb59c88f7d4ed8936a1be","src/time.rs":"957845f8c689aec3c5dcf1af8bbc274a28ed5a214e4ee31ec8a89ed5eea0d3f1","src/ucont
 ext.rs":"10fdfebcecafa8d1c6cf573a5768adc07b87e9ff52a0bdc2527e77f73608f264","src/unistd.rs":"9c2b170f2b217393e571fb8021e000dfec4a5d99e170e11532a665163ecf3d54","test/common/mod.rs":"a26ecf30fc06008bab21d96eabf711bb0c41e8b50fe4c1f35cb2797ef405296c","test/sys/mod.rs":"c6f6a376fca73025bd76043a1739f54d24e856d4d0af9c58cc2b9d730ab87144","test/sys/test_aio.rs":"f21c157a07a29d60b0d68baa78ce24b352a19a35eaced0a792f62fa16d38617f","test/sys/test_aio_drop.rs":"eb086fcebd53ec82359ed7323f039b16ef7abced66b111f4876486fb058476e5","test/sys/test_epoll.rs":"35093d0cb1096a934dfc4f6efc737eadc4bdc2e2134d2a879061374a51b10c97","test/sys/test_inotify.rs":"a4f804bcf414b6635d9863c8534769a609009c451c3476cc839cdc30c439b3b1","test/sys/test_ioctl.rs":"39ddd52b27d942ab1b4018d213a378fb221598febc8fc7759ae5e6f746364396","test/sys/test_lio_listio_resubmit.rs":"29718e5fd04ef041125db4963f518f6f518b50436ea2df91e44c9c6b9418b704","test/sys/test_mman.rs":"b129b1d40d7a6e23cfc10956f9aa689d578a745f82fa267d24c40475063b592c","test/
 sys/test_pthread.rs":"891726053083bf488655eca1518630b08fa7c5937433fb5e446a9eed181ff7c5","test/sys/test_ptrace.rs":"46e51267cc93e45894a1e5a194563af5fb65a170dca95ad7cf9110520d764703","test/sys/test_select.rs":"7ece285a78cb66852ba8e89cac82c2d4fcff7d17a5f35e282cc52a09f5820daf","test/sys/test_signal.rs":"753f2ccbfcf2c5353a75b1e48d746a07c1949defba515c0ceee589ad1ed0aff6","test/sys/test_signalfd.rs":"2068a028c88395ff51c09e43b18c03d16e2d851f1d26ca1d121cdb5cb050f5c5","test/sys/test_socket.rs":"0f5fe9637f196cef459aadee27e449e5f9f968c10bf8dd017763c607cb6261d3","test/sys/test_sockopt.rs":"3334e12322e8b4e7c095ddc4a40a2d0e73a0d3a6e1820a6e0970eb8e1136c6de","test/sys/test_sysinfo.rs":"1e1bea9130fe38ccb07cd0ad7334c7be1e45efc33f7656a5973f8cad7126f225","test/sys/test_termios.rs":"93cd5cc181f1d8cef5c69aa23ddfabbf0480369cffab523e677c81e208998328","test/sys/test_timerfd.rs":"fcada956abd981e4d846da58e5640c5705b16026d47bccd1d603fae765ad10db","test/sys/test_uio.rs":"ae915c03e4f64ce370ae46f5dbe37834dae2849bb9
 fa7961872cec50f45de1f4","test/sys/test_wait.rs":"1fefed60ea3f9c5d8d4518e1d7a122d50aad44c2bd87873ac9ddc31ecdcc5a39","test/test.rs":"be9c29b8a8c9669b6674746ac8065c828a5d1d40ba41226846fe964310a18188","test/test_clearenv.rs":"45ca548035b3c20ec87314715feaba2be973709a635d85b8cde46fd1d9f1ecd4","test/test_dir.rs":"e0dc7c317871eda3873a5d9df801c2ebb34cd958210c42a15f8dff623f05cae0","test/test_fcntl.rs":"e60c1dde6d0a6fde7a52cf98332e5b96fef5749868f0313cb7082bda7a66adb9","test/test_kmod/hello_mod/Makefile":"0219f7bce0603f97d997fb377ca071966c90333ecc665e78a54dfeb97a9c811b","test/test_kmod/hello_mod/hello.c":"bcac6b19c5bd807e1f3878c15e426acc85785a8ade9840c3bb4d068635c9188c","test/test_kmod/mod.rs":"07f5445812593c994d1c25d5c8669aa3c4b1750f3b8ed2c1ddb1c661809983dc","test/test_mount.rs":"55503e8b28f77b45d755d549375cab34fa3a3cc9b94cbb23cfbd4426c5d9cb9c","test/test_mq.rs":"1020a4eb2f88cc29c59c44ad965d0573fba2beeb4c8986060aac56de99eea63c","test/test_net.rs":"ec6d580b87292519d514b0236bdd5abdd576fcf4835cfe
 49ed1ddb47c5f1aea3","test/test_nix_path.rs":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","test/test_poll.rs":"fbcf1780447f75a0177b4f47ba3d99b68f4324059ff66d993034ae5035c6d3ef","test/test_pty.rs":"56198cb9537ec3409717acecb133a49eb48bfc180c135ff0296974ec466d1171","test/test_ptymaster_drop.rs":"d162510cc96b8b7389d8bc34e097db1c80b84b5070c1d16f15b053ffd20cfa17","test/test_sched.rs":"f8ad92eb554164b0f92428f716db99040186d741cc6e1976f7930f099652f70c","test/test_sendfile.rs":"e0cbabbd34052ccaa03d6555d5631686aa076728f6378ee90f7ecec68f891144","test/test_stat.rs":"9668fc1f894b7f8a60dfddbdaef4bc833463e4e0cf04c1cff7f8c0569a226ad2","test/test_time.rs":"199b1c89d373e9398cca97f83ecd6459c6bd5ba7adca28013d9109d5cbad03f3","test/test_unistd.rs":"9bf047d877fd7c0826a2241737574923c3fd102a6b143b6d9710f52af5655588"},"package":"f5e06129fb611568ef4e868c14b326274959aa70ff7776e9d55323531c374945"}
+\ No newline at end of file
+diff --git a/third_party/rust/nix/CHANGELOG.md b/third_party/rust/nix/CHANGELOG.md
+index d93a5ce6bbfc9..234f2307c6d36 100644
+--- a/third_party/rust/nix/CHANGELOG.md
++++ b/third_party/rust/nix/CHANGELOG.md
+@@ -2,12 +2,316 @@
+ 
+ All notable changes to this project will be documented in this file.
+ This project adheres to [Semantic Versioning](http://semver.org/).
++This project adheres to [Semantic Versioning](https://semver.org/).
+ 
+-## [Unreleased] - ReleaseDate
++## [0.20.2] - 28 September 2021
+ ### Added
+ ### Changed
+ ### Fixed
++
++- Fixed buffer overflow in `unistd::getgrouplist`.
++  (#[1545](https://github.com/nix-rust/nix/pull/1545))
++
++## [0.20.1] - 13 August 2021
++### Added
++### Changed
++### Fixed
++
++- Locked bitflags to < 1.3.0 to fix the build with rust < 1.46.0.
++
++### Removed
++
++- Removed a couple of termios constants on redox that were never actually
++  supported.
++  (#[1483](https://github.com/nix-rust/nix/pull/1483))
++
++## [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
++  (#[1289](https://github.com/nix-rust/nix/pull/1289))
++- Added `clock_gettime`, `clock_settime`, `clock_getres`,
++  `clock_getcpuclockid` functions and `ClockId` struct.
++  (#[1281](https://github.com/nix-rust/nix/pull/1281))
++- Added wrapper functions for `PTRACE_SYSEMU` and `PTRACE_SYSEMU_SINGLESTEP`.
++  (#[1300](https://github.com/nix-rust/nix/pull/1300))
++- Add support for Vsock on Android rather than just Linux.
++  (#[1301](https://github.com/nix-rust/nix/pull/1301))
++- Added `TCP_KEEPCNT` and `TCP_KEEPINTVL` TCP keepalive options.
++  (#[1283](https://github.com/nix-rust/nix/pull/1283))
++### Changed
++- Expose `SeekData` and `SeekHole` on all Linux targets
++  (#[1284](https://github.com/nix-rust/nix/pull/1284))
++- Changed unistd::{execv,execve,execvp,execvpe,fexecve,execveat} to take both `&[&CStr]` and `&[CString]` as its list argument(s).
++  (#[1278](https://github.com/nix-rust/nix/pull/1278))
++- Made `unistd::fork` an unsafe funtion, bringing it in line with [libstd's decision](https://github.com/rust-lang/rust/pull/58059).
++  (#[1293](https://github.com/nix-rust/nix/pull/1293))
++### Fixed
++### Removed
++
++## [0.18.0] - 26 July 2020
++### Added
++- Added `fchown(2)` wrapper.
++  (#[1257](https://github.com/nix-rust/nix/pull/1257))
++- Added support on linux systems for `MAP_HUGE_`_`SIZE`_ family of flags.
++  (#[1211](https://github.com/nix-rust/nix/pull/1211))
++- Added support for `F_OFD_*` `fcntl` commands on Linux and Android.
++  (#[1195](https://github.com/nix-rust/nix/pull/1195))
++- Added `env::clearenv()`: calls `libc::clearenv` on platforms
++  where it's available, and clears the environment of all variables
++  via `std::env::vars` and `std::env::remove_var` on others.
++  (#[1185](https://github.com/nix-rust/nix/pull/1185))
++- `FsType` inner value made public.
++  (#[1187](https://github.com/nix-rust/nix/pull/1187))
++- Added `unistd::setfsuid` and `unistd::setfsgid` to set the user or group
++  identity for filesystem checks per-thread.
++  (#[1163](https://github.com/nix-rust/nix/pull/1163))
++- 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
++  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))
++- Added support for `SCM_CREDS` messages (`UnixCredentials`) on FreeBSD/DragonFly
++  (#[1216](https://github.com/nix-rust/nix/pull/1216))
++- Added `BindToDevice` socket option (sockopt) on Linux
++  (#[1233](https://github.com/nix-rust/nix/pull/1233))
++- Added `EventFilter` bitflags for `EV_DISPATCH` and `EV_RECEIPT` on OpenBSD.
++  (#[1252](https://github.com/nix-rust/nix/pull/1252))
++- Added support for `Ipv4PacketInfo` and `Ipv6PacketInfo` to `ControlMessage`.
++  (#[1222](https://github.com/nix-rust/nix/pull/1222))
++- `CpuSet` and `UnixCredentials` now implement `Default`.
++  (#[1244](https://github.com/nix-rust/nix/pull/1244))
++- Added `unistd::ttyname`
++  (#[1259](https://github.com/nix-rust/nix/pull/1259))
++- Added support for `Ipv4PacketInfo` and `Ipv6PacketInfo` to `ControlMessage` for iOS and Android.
++  (#[1265](https://github.com/nix-rust/nix/pull/1265))
++- Added support for `TimerFd`.
++  (#[1261](https://github.com/nix-rust/nix/pull/1261))
++
++### Changed
++- Changed `fallocate` return type from `c_int` to `()` (#[1201](https://github.com/nix-rust/nix/pull/1201))
++- Enabled `sys::ptrace::setregs` and `sys::ptrace::getregs` on x86_64-unknown-linux-musl target
++  (#[1198](https://github.com/nix-rust/nix/pull/1198))
++- On Linux, `ptrace::write` is now an `unsafe` function. Caveat programmer.
++  (#[1245](https://github.com/nix-rust/nix/pull/1245))
++- `execv`, `execve`, `execvp` and `execveat` in `::nix::unistd` and `reboot` in
++  `::nix::sys::reboot` now return `Result<Infallible>` instead of `Result<Void>` (#[1239](https://github.com/nix-rust/nix/pull/1239))
++- `sys::socket::sockaddr_storage_to_addr` is no longer `unsafe`.  So is
++  `offset_of!`.
++- `sys::socket::sockaddr_storage_to_addr`, `offset_of!`, and `Errno::clear` are
++  no longer `unsafe`.
++- `SockAddr::as_ffi_pair`,`sys::socket::sockaddr_storage_to_addr`, `offset_of!`,
++  and `Errno::clear` are no longer `unsafe`.
++  (#[1244](https://github.com/nix-rust/nix/pull/1244))
++- Several `Inotify` methods now take `self` by value instead of by reference
++  (#[1244](https://github.com/nix-rust/nix/pull/1244))
++- `nix::poll::ppoll`: `timeout` parameter is now optional, None is equivalent for infinite timeout.
++
++### Fixed
++
++- Fixed `getsockopt`.  The old code produced UB which triggers a panic with
++  Rust 1.44.0.
++  (#[1214](https://github.com/nix-rust/nix/pull/1214))
++
++- Fixed a bug in nix::unistd that would result in an infinite loop
++  when a group or user lookup required a buffer larger than
++  16KB. (#[1198](https://github.com/nix-rust/nix/pull/1198))
++- Fixed unaligned casting of `cmsg_data` to `af_alg_iv` (#[1206](https://github.com/nix-rust/nix/pull/1206))
++- Fixed `readlink`/`readlinkat` when reading symlinks longer than `PATH_MAX` (#[1231](https://github.com/nix-rust/nix/pull/1231))
++- `PollFd`, `EpollEvent`, `IpMembershipRequest`, `Ipv6MembershipRequest`,
++  `TimeVal`, and `IoVec` are now `repr(transparent)`.  This is required for
++  correctness's sake across all architectures and compilers, though now bugs
++  have been reported so far.
++  (#[1243](https://github.com/nix-rust/nix/pull/1243))
++- Fixed unaligned pointer read in `Inotify::read_events`.
++  (#[1244](https://github.com/nix-rust/nix/pull/1244))
++
++### Removed
++
++- Removed `sys::socket::addr::from_libc_sockaddr` from the public API.
++  (#[1215](https://github.com/nix-rust/nix/pull/1215))
++- Removed `sys::termios::{get_libc_termios, get_libc_termios_mut, update_wrapper`
++  from the public API. These were previously hidden in the docs but still usable
++  by downstream.
++  (#[1235](https://github.com/nix-rust/nix/pull/1235))
++
++- Nix no longer implements `NixPath` for `Option<P> where P: NixPath`.  Most
++  Nix functions that accept `NixPath` arguments can't do anything useful with
++  `None`.  The exceptions (`mount` and `quotactl_sync`) already take explicitly
++  optional arguments.
++  (#[1242](https://github.com/nix-rust/nix/pull/1242))
++
++- Removed `unistd::daemon` and `unistd::pipe2` on OSX and ios
++  (#[1255](https://github.com/nix-rust/nix/pull/1255))
++
++- Removed `sys::event::FilterFlag::NOTE_EXIT_REPARENTED` and
++  `sys::event::FilterFlag::NOTE_REAP` on OSX and ios.
++  (#[1255](https://github.com/nix-rust/nix/pull/1255))
++
++- Removed `sys::ptrace::ptrace` on Android and Linux.
++  (#[1255](https://github.com/nix-rust/nix/pull/1255))
++
++- Dropped support for powerpc64-unknown-linux-gnu
++  (#[1266](https://github.com/nix-rust/nix/pull/1268))
++
++## [0.17.0] - 3 February 2020
++### Added
++- Add `CLK_TCK` to `SysconfVar`
++  (#[1177](https://github.com/nix-rust/nix/pull/1177))
++### Changed
++### Fixed
++### Removed
++- Removed deprecated Error::description from error types
++  (#[1175](https://github.com/nix-rust/nix/pull/1175))
++
++## [0.16.1] - 23 December 2019
++### Added
++### Changed
++### Fixed
++
++- Fixed the build for OpenBSD
++  (#[1168](https://github.com/nix-rust/nix/pull/1168))
++
++### Removed
++
++## [0.16.0] - 1 December 2019
++### Added
++- Added `ptrace::seize()`: similar to `attach()` on Linux
++  but with better-defined semantics.
++  (#[1154](https://github.com/nix-rust/nix/pull/1154))
++
++- Added `Signal::as_str()`: returns signal name as `&'static str`
++  (#[1138](https://github.com/nix-rust/nix/pull/1138))
++
++- Added `posix_fallocate`.
++  ([#1105](https://github.com/nix-rust/nix/pull/1105))
++
++- Implemented `Default` for `FdSet`
++  ([#1107](https://github.com/nix-rust/nix/pull/1107))
++
++- Added `NixPath::is_empty`.
++  ([#1107](https://github.com/nix-rust/nix/pull/1107))
++
++- Added `mkfifoat`
++  ([#1133](https://github.com/nix-rust/nix/pull/1133))
++
++- Added `User::from_uid`, `User::from_name`, `User::from_gid` and
++  `Group::from_name`,
++  ([#1139](https://github.com/nix-rust/nix/pull/1139))
++
++- Added `linkat`
++  ([#1101](https://github.com/nix-rust/nix/pull/1101))
++
++- Added `sched_getaffinity`.
++  ([#1148](https://github.com/nix-rust/nix/pull/1148))
++
++- Added optional `Signal` argument to `ptrace::{detach, syscall}` for signal
++  injection. ([#1083](https://github.com/nix-rust/nix/pull/1083))
++
++### Changed
++- `sys::termios::BaudRate` now implements `TryFrom<speed_t>` instead of
++  `From<speed_t>`.  The old `From` implementation would panic on failure.
++  ([#1159](https://github.com/nix-rust/nix/pull/1159))
++
++- `sys::socket::ControlMessage::ScmCredentials` and
++  `sys::socket::ControlMessageOwned::ScmCredentials` now wrap `UnixCredentials`
++  rather than `libc::ucred`.
++  ([#1160](https://github.com/nix-rust/nix/pull/1160))
++
++- `sys::socket::recvmsg` now takes a plain `Vec` instead of a `CmsgBuffer`
++  implementor.  If you were already using `cmsg_space!`, then you needn't worry.
++  ([#1156](https://github.com/nix-rust/nix/pull/1156))
++
++- `sys::socket::recvfrom` now returns
++  `Result<(usize, Option<SockAddr>)>` instead of `Result<(usize, SockAddr)>`.
++  ([#1145](https://github.com/nix-rust/nix/pull/1145))
++
++- `Signal::from_c_int` has been replaced by `Signal::try_from`
++  ([#1113](https://github.com/nix-rust/nix/pull/1113))
++
++- Changed `readlink` and `readlinkat` to return `OsString`
++  ([#1109](https://github.com/nix-rust/nix/pull/1109))
++
++  ```rust
++  # use nix::fcntl::{readlink, readlinkat};
++  // the buffer argument of `readlink` and `readlinkat` has been removed,
++  // and the return value is now an owned type (`OsString`).
++  // Existing code can be updated by removing the buffer argument
++  // and removing any clone or similar operation on the output
++
++  // old code `readlink(&path, &mut buf)` can be replaced with the following
++  let _: OsString = readlink(&path);
++
++  // old code `readlinkat(dirfd, &path, &mut buf)` can be replaced with the following
++  let _: OsString = readlinkat(dirfd, &path);
++  ```
++
++- Minimum supported Rust version is now 1.36.0.
++  ([#1108](https://github.com/nix-rust/nix/pull/1108))
++
++- `Ipv4Addr::octets`, `Ipv4Addr::to_std`, `Error::as_errno`,
++  `ForkResult::is_child`, `ForkResult::is_parent`, `Gid::as_raw`,
++  `Uid::is_root`, `Uid::as_raw`, `Pid::as_raw`, and `PollFd::revents` now take
++  `self` by value.
++  ([#1107](https://github.com/nix-rust/nix/pull/1107))
++
++- Type `&CString` for parameters of `exec(v|ve|vp|vpe|veat)` are changed to `&CStr`.
++  ([#1121](https://github.com/nix-rust/nix/pull/1121))
++
++### Fixed
++- Fix length of abstract socket addresses
++  ([#1120](https://github.com/nix-rust/nix/pull/1120))
++
++- Fix initialization of msghdr in recvmsg/sendmsg when built with musl
++  ([#1136](https://github.com/nix-rust/nix/pull/1136))
++
+ ### Removed
++- Remove the deprecated `CmsgSpace`.
++  ([#1156](https://github.com/nix-rust/nix/pull/1156))
+ 
+ ## [0.15.0] - 10 August 2019
+ ### Added
+diff --git a/third_party/rust/nix/CONTRIBUTING.md b/third_party/rust/nix/CONTRIBUTING.md
+index 03a1f630dbb06..55990c4f1a24f 100644
+--- a/third_party/rust/nix/CONTRIBUTING.md
++++ b/third_party/rust/nix/CONTRIBUTING.md
+@@ -76,21 +76,21 @@ add a test that would have failed without the fix.
+ 
+ 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/third_party/rust/nix/CONVENTIONS.md b/third_party/rust/nix/CONVENTIONS.md
+index 48daa937345d2..2461085eb664a 100644
+--- a/third_party/rust/nix/CONVENTIONS.md
++++ b/third_party/rust/nix/CONVENTIONS.md
+@@ -76,12 +76,11 @@ to parameters of functions by [enumerations][enum].
+ 
+ Whenever we need to use a [libc][libc] function to properly initialize a
+ variable and said function allows us to use uninitialized memory, we use
+-[`std::mem::uninitialized`][std_uninitialized] (or [`core::mem::uninitialized`][core_uninitialized])
+-when defining the variable. This allows us to avoid the overhead incurred by
+-zeroing or otherwise initializing the variable.
++[`std::mem::MaybeUninit`][std_MaybeUninit] when defining the variable. This
++allows us to avoid the overhead incurred by zeroing or otherwise initializing
++the variable.
+ 
+ [bitflags]: https://crates.io/crates/bitflags/
+-[core_uninitialized]: https://doc.rust-lang.org/core/mem/fn.uninitialized.html
+ [enum]: https://doc.rust-lang.org/reference.html#enumerations
+ [libc]: https://crates.io/crates/libc/
+-[std_uninitialized]: https://doc.rust-lang.org/std/mem/fn.uninitialized.html
++[std_MaybeUninit]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html
+diff --git a/third_party/rust/nix/Cargo.toml b/third_party/rust/nix/Cargo.toml
+index 555b99020d68f..456bdca9c2599 100644
+--- a/third_party/rust/nix/Cargo.toml
++++ b/third_party/rust/nix/Cargo.toml
+@@ -3,22 +3,24 @@
+ # When uploading crates to the registry Cargo will automatically
+ # "normalize" Cargo.toml files for maximal compatibility
+ # with all versions of Cargo and also rewrite `path` dependencies
+-# to registry (e.g., crates.io) dependencies
++# to registry (e.g., crates.io) dependencies.
+ #
+-# If you believe there's an error in this file please file an
+-# issue against the rust-lang/cargo repository. If you're
+-# editing this file be aware that the upstream Cargo.toml
+-# will likely look very different (and much more reasonable)
++# If you are reading this file be aware that the original Cargo.toml
++# will likely look very different (and much more reasonable).
++# See Cargo.toml.orig for the original contents.
+ 
+ [package]
++edition = "2018"
+ name = "nix"
+-version = "0.15.0"
++version = "0.20.2"
+ 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"
+@@ -28,6 +30,10 @@ path = "test/test.rs"
+ name = "test-aio-drop"
+ path = "test/sys/test_aio_drop.rs"
+ 
++[[test]]
++name = "test-clearenv"
++path = "test/test_clearenv.rs"
++
+ [[test]]
+ name = "test-lio-listio-resubmit"
+ path = "test/sys/test_lio_listio_resubmit.rs"
+@@ -41,17 +47,14 @@ harness = false
+ name = "test-ptymaster-drop"
+ path = "test/test_ptymaster_drop.rs"
+ [dependencies.bitflags]
+-version = "1.0"
++version = ">= 1.1.0, < 1.3.0"
+ 
+ [dependencies.cfg-if]
+-version = "0.1.2"
++version = "1.0"
+ 
+ [dependencies.libc]
+-version = "0.2.60"
++version = "0.2.99"
+ features = ["extra_traits"]
+-
+-[dependencies.void]
+-version = "1.0.2"
+ [dev-dependencies.bytes]
+ version = "0.4.8"
+ 
+@@ -59,12 +62,17 @@ version = "0.4.8"
+ version = "1.2"
+ 
+ [dev-dependencies.rand]
+-version = ">= 0.6, < 0.7"
++version = "0.6"
++
++[dev-dependencies.semver]
++version = "0.9.0"
+ 
+ [dev-dependencies.tempfile]
+-version = ">= 3.0.5, < 3.0.9"
++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(not(target_os = \"redox\"))".dependencies.memoffset]
++version = "0.6.3"
+ [target."cfg(target_os = \"dragonfly\")".build-dependencies.cc]
+ version = "1"
+ [target."cfg(target_os = \"freebsd\")".dev-dependencies.sysctl]
+diff --git a/third_party/rust/nix/README.md b/third_party/rust/nix/README.md
+index 0e540ba5b968e..b4909ea4345cc 100644
+--- a/third_party/rust/nix/README.md
++++ b/third_party/rust/nix/README.md
+@@ -1,6 +1,6 @@
+ # Rust bindings to *nix APIs
+ 
+-[![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)
+ 
+ [Documentation (Releases)](https://docs.rs/nix/)
+@@ -50,7 +50,6 @@ Tier 1:
+   * 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
+@@ -58,7 +57,6 @@ Tier 1:
+   * mips64-unknown-linux-gnuabi64
+   * mips64el-unknown-linux-gnuabi64
+   * mipsel-unknown-linux-gnu
+-  * powerpc64-unknown-linux-gnu
+   * powerpc64le-unknown-linux-gnu
+   * x86_64-apple-darwin
+   * x86_64-unknown-freebsd
+@@ -74,6 +72,7 @@ Tier 2:
+   * armv7-linux-androideabi
+   * armv7s-apple-ios
+   * i386-apple-ios
++  * i686-apple-darwin
+   * i686-linux-android
+   * powerpc-unknown-linux-gnu
+   * s390x-unknown-linux-gnu
+@@ -81,21 +80,20 @@ Tier 2:
+   * x86_64-linux-android
+   * x86_64-unknown-netbsd
+ 
++Tier 3:
++  * x86_64-fuchsia
++  * x86_64-unknown-redox
++  * x86_64-unknown-linux-gnux32
++
+ ## Usage
+ 
+-`nix` requires Rust 1.31.0 or newer.
++`nix` requires Rust 1.40.0 or newer.
+ 
+-To use `nix`, first add this to your `Cargo.toml`:
++To use `nix`, add this to your `Cargo.toml`:
+ 
+ ```toml
+ [dependencies]
+-nix = "0.15.0"
+-```
+-
+-Then, add this to your crate root:
+-
+-```rust,ignore
+-extern crate nix;
++nix = "0.20.2"
+ ```
+ 
+ ## Contributing
+diff --git a/third_party/rust/nix/src/dir.rs b/third_party/rust/nix/src/dir.rs
+index 1820b5330ff60..7d4ab82f79e0d 100644
+--- a/third_party/rust/nix/src/dir.rs
++++ b/third_party/rust/nix/src/dir.rs
+@@ -1,10 +1,10 @@
+-use {Error, NixPath, Result};
+-use errno::Errno;
+-use fcntl::{self, OFlag};
+-use libc;
++use crate::{Error, NixPath, Result};
++use crate::errno::Errno;
++use crate::fcntl::{self, OFlag};
+ use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd};
+-use std::{ffi, ptr};
+-use sys;
++use std::ptr;
++use std::ffi;
++use crate::sys;
+ 
+ #[cfg(target_os = "linux")]
+ use libc::{dirent64 as dirent, readdir64_r as readdir_r};
+@@ -25,7 +25,7 @@ use libc::{dirent, readdir_r};
+ ///    * 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 AsRawFd for Dir {
+ 
+ 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,23 +121,7 @@ impl<'d> Iterator for Iter<'d> {
+     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: Entry = Entry(::std::mem::uninitialized());
+-            let mut result = ptr::null_mut();
+-            if let Err(e) = Errno::result(readdir_r((self.0).0.as_ptr(), &mut ent.0, &mut result)) {
+-                return Some(Err(e));
+-            }
+-            if result == ptr::null_mut() {
+-                return None;
+-            }
+-            assert_eq!(result, &mut ent.0 as *mut dirent);
+-            return Some(Ok(ent));
+-        }
++        next(self.0)
+     }
+ }
+ 
+@@ -122,10 +131,48 @@ impl<'d> Drop for Iter<'d> {
+     }
+ }
+ 
++/// 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.
+ #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
++#[repr(transparent)]
+ pub struct Entry(dirent);
+ 
+ #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
+@@ -165,7 +212,7 @@ impl Entry {
+                   target_os = "macos",
+                   target_os = "solaris")))]
+     pub fn ino(&self) -> u64 {
+-        self.0.d_fileno as u64
++        u64::from(self.0.d_fileno)
+     }
+ 
+     /// Returns the bare file name of this directory entry without any other leading path component.
+diff --git a/third_party/rust/nix/src/env.rs b/third_party/rust/nix/src/env.rs
+new file mode 100644
+index 0000000000000..f144dfedd0c1a
+--- /dev/null
++++ b/third_party/rust/nix/src/env.rs
+@@ -0,0 +1,53 @@
++use cfg_if::cfg_if;
++use crate::{Error, Result};
++
++/// Clear the environment of all name-value pairs.
++///
++/// On platforms where libc provides `clearenv()`, it will be used. libc's
++/// `clearenv()` is documented to return an error code but not set errno; if the
++/// return value indicates a failure, this function will return
++/// `Error::UnsupportedOperation`.
++///
++/// On platforms where libc does not provide `clearenv()`, a fallback
++/// implementation will be used that iterates over all environment variables and
++/// removes them one-by-one.
++///
++/// # Safety
++///
++/// This function is not threadsafe and can cause undefined behavior in
++/// combination with `std::env` or other program components that access the
++/// environment. See, for example, the discussion on `std::env::remove_var`; this
++/// function is a case of an "inherently unsafe non-threadsafe API" dealing with
++/// the environment.
++///
++///  The caller must ensure no other threads access the process environment while
++///  this function executes and that no raw pointers to an element of libc's
++///  `environ` is currently held. The latter is not an issue if the only other
++///  environment access in the program is via `std::env`, but the requirement on
++///  thread safety must still be upheld.
++pub unsafe fn clearenv() -> Result<()> {
++    let ret;
++    cfg_if! {
++        if #[cfg(any(target_os = "fuchsia",
++                     target_os = "wasi",
++                     target_env = "wasi",
++                     target_env = "uclibc",
++                     target_os = "linux",
++                     target_os = "android",
++                     target_os = "emscripten"))] {
++            ret = libc::clearenv();
++        } else {
++            use std::env;
++            for (name, _) in env::vars_os() {
++                env::remove_var(name);
++            }
++            ret = 0;
++        }
++    }
++
++    if ret == 0 {
++        Ok(())
++    } else {
++        Err(Error::UnsupportedOperation)
++    }
++}
+diff --git a/third_party/rust/nix/src/errno.rs b/third_party/rust/nix/src/errno.rs
+index 6a2447bc52675..e5c709252025c 100644
+--- a/third_party/rust/nix/src/errno.rs
++++ b/third_party/rust/nix/src/errno.rs
+@@ -1,8 +1,7 @@
+-#[cfg(not(target_os = "dragonfly"))]
+-use libc;
++use cfg_if::cfg_if;
+ use libc::{c_int, c_void};
+ use std::{fmt, io, error};
+-use {Error, Result};
++use crate::{Error, Result};
+ 
+ pub use self::consts::*;
+ 
+@@ -13,32 +12,16 @@ cfg_if! {
+         unsafe fn errno_location() -> *mut c_int {
+             libc::__error()
+         }
+-    } else if #[cfg(target_os = "dragonfly")] {
+-        // DragonFly uses a thread-local errno variable, but #[thread_local] is
+-        // feature-gated and not available in stable Rust as of this writing
+-        // (Rust 1.21.0). We have to use a C extension to access it
+-        // (src/errno_dragonfly.c).
+-        //
+-        // Tracking issue for `thread_local` stabilization:
+-        //
+-        //     https://github.com/rust-lang/rust/issues/29594
+-        //
+-        // Once this becomes stable, we can remove build.rs,
+-        // src/errno_dragonfly.c, and use:
+-        //
+-        //     extern { #[thread_local] static errno: c_int; }
+-        //
+-        #[link(name="errno_dragonfly", kind="static")]
+-        extern {
+-            pub fn errno_location() -> *mut c_int;
+-        }
+     } else if #[cfg(any(target_os = "android",
+                         target_os = "netbsd",
+                         target_os = "openbsd"))] {
+         unsafe fn errno_location() -> *mut c_int {
+             libc::__errno()
+         }
+-    } else if #[cfg(target_os = "linux")] {
++    } else if #[cfg(any(target_os = "linux",
++                        target_os = "redox",
++                        target_os = "dragonfly",
++                        target_os = "fuchsia"))] {
+         unsafe fn errno_location() -> *mut c_int {
+             libc::__errno_location()
+         }
+@@ -46,8 +29,11 @@ cfg_if! {
+ }
+ 
+ /// Sets the platform-specific errno to no-error
+-unsafe fn clear() -> () {
+-    *errno_location() = 0;
++fn clear() {
++    // Safe because errno is a thread-local variable
++    unsafe {
++        *errno_location() = 0;
++    }
+ }
+ 
+ /// Returns the platform-specific value of errno
+@@ -70,7 +56,7 @@ impl Errno {
+         from_i32(err)
+     }
+ 
+-    pub unsafe fn clear() -> () {
++    pub fn clear() {
+         clear()
+     }
+ 
+@@ -111,11 +97,7 @@ impl ErrnoSentinel for libc::sighandler_t {
+     fn sentinel() -> Self { libc::SIG_ERR }
+ }
+ 
+-impl error::Error for Errno {
+-    fn description(&self) -> &str {
+-        self.desc()
+-    }
+-}
++impl error::Error for Errno {}
+ 
+ impl fmt::Display for Errno {
+     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+@@ -207,200 +189,263 @@ fn desc(errno: Errno) -> &'static str {
+         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"))]
++        #[cfg(any(target_os = "linux", target_os = "android",
++                  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"))]
+         EDOOFUS         => "Programming error",
+ 
+-        #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++        #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "redox"))]
+         EMULTIHOP       => "Multihop attempted",
+ 
+-        #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++        #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "redox"))]
+         ENOLINK         => "Link has been severed",
+ 
+         #[cfg(target_os = "freebsd")]
+@@ -416,12 +461,13 @@ fn desc(errno: Errno) -> &'static str {
+ 
+         #[cfg(any(target_os = "macos", target_os = "freebsd",
+                   target_os = "dragonfly", target_os = "ios",
+-                  target_os = "openbsd", target_os = "netbsd"))]
++                  target_os = "openbsd", target_os = "netbsd",
++                  target_os = "redox"))]
+         EOVERFLOW       => "Value too large to be stored in data type",
+ 
+         #[cfg(any(target_os = "macos", target_os = "freebsd",
+                   target_os = "dragonfly", target_os = "ios",
+-                  target_os = "netbsd"))]
++                  target_os = "netbsd", target_os = "redox"))]
+         EILSEQ          => "Illegal byte sequence",
+ 
+         #[cfg(any(target_os = "macos", target_os = "freebsd",
+@@ -431,12 +477,14 @@ fn desc(errno: Errno) -> &'static str {
+ 
+         #[cfg(any(target_os = "macos", target_os = "freebsd",
+                   target_os = "dragonfly", target_os = "ios",
+-                  target_os = "openbsd", target_os = "netbsd"))]
++                  target_os = "openbsd", target_os = "netbsd",
++                  target_os = "redox"))]
+         EBADMSG         => "Bad message",
+ 
+         #[cfg(any(target_os = "macos", target_os = "freebsd",
+                   target_os = "dragonfly", target_os = "ios",
+-                  target_os = "openbsd", target_os = "netbsd"))]
++                  target_os = "openbsd", target_os = "netbsd",
++                  target_os = "redox"))]
+         EPROTO          => "Protocol error",
+ 
+         #[cfg(any(target_os = "macos", target_os = "freebsd",
+@@ -459,22 +507,26 @@ fn desc(errno: Errno) -> &'static str {
+ 
+         #[cfg(any(target_os = "macos", target_os = "freebsd",
+                   target_os = "dragonfly", target_os = "ios",
+-                  target_os = "openbsd", target_os = "netbsd"))]
++                  target_os = "openbsd", target_os = "netbsd",
++                  target_os = "redox"))]
+         EUSERS          => "Too many users",
+ 
+         #[cfg(any(target_os = "macos", target_os = "freebsd",
+                   target_os = "dragonfly", target_os = "ios",
+-                  target_os = "openbsd", target_os = "netbsd"))]
++                  target_os = "openbsd", target_os = "netbsd",
++                  target_os = "redox"))]
+         EDQUOT          => "Disc quota exceeded",
+ 
+         #[cfg(any(target_os = "macos", target_os = "freebsd",
+                   target_os = "dragonfly", target_os = "ios",
+-                  target_os = "openbsd", target_os = "netbsd"))]
++                  target_os = "openbsd", target_os = "netbsd",
++                  target_os = "redox"))]
+         ESTALE          => "Stale NFS file handle",
+ 
+         #[cfg(any(target_os = "macos", target_os = "freebsd",
+                   target_os = "dragonfly", target_os = "ios",
+-                  target_os = "openbsd", target_os = "netbsd"))]
++                  target_os = "openbsd", target_os = "netbsd",
++                  target_os = "redox"))]
+         EREMOTE         => "Too many levels of remote in path",
+ 
+         #[cfg(any(target_os = "macos", target_os = "freebsd",
+@@ -514,7 +566,8 @@ fn desc(errno: Errno) -> &'static str {
+ 
+         #[cfg(any(target_os = "macos", target_os = "freebsd",
+                   target_os = "dragonfly", target_os = "ios",
+-                  target_os = "openbsd", target_os = "netbsd"))]
++                  target_os = "openbsd", target_os = "netbsd",
++                  target_os = "redox"))]
+         ECANCELED       => "Operation canceled",
+ 
+         #[cfg(any(target_os = "macos", target_os = "ios"))]
+@@ -538,19 +591,23 @@ fn desc(errno: Errno) -> &'static str {
+         #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
+         EMULTIHOP       => "Reserved",
+ 
+-        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
++        #[cfg(any(target_os = "macos", target_os = "ios",
++                  target_os = "netbsd", target_os = "redox"))]
+         ENODATA         => "No message available on STREAM",
+ 
+         #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
+         ENOLINK         => "Reserved",
+ 
+-        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
++        #[cfg(any(target_os = "macos", target_os = "ios",
++                  target_os = "netbsd", target_os = "redox"))]
+         ENOSR           => "No STREAM resources",
+ 
+-        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
++        #[cfg(any(target_os = "macos", target_os = "ios",
++                  target_os = "netbsd", target_os = "redox"))]
+         ENOSTR          => "Not a STREAM",
+ 
+-        #[cfg(any(target_os = "macos", target_os = "ios", target_os = "netbsd"))]
++        #[cfg(any(target_os = "macos", target_os = "ios",
++                  target_os = "netbsd", target_os = "redox"))]
+         ETIME           => "STREAM ioctl timeout",
+ 
+         #[cfg(any(target_os = "macos", target_os = "ios"))]
+@@ -573,10 +630,9 @@ fn desc(errno: Errno) -> &'static str {
+     }
+ }
+ 
+-#[cfg(any(target_os = "linux", target_os = "android"))]
++#[cfg(any(target_os = "linux", target_os = "android",
++          target_os = "fuchsia"))]
+ mod consts {
+-    use libc;
+-
+     #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+     #[repr(i32)]
+     pub enum Errno {
+@@ -864,8 +920,6 @@ mod consts {
+ 
+ #[cfg(any(target_os = "macos", target_os = "ios"))]
+ mod consts {
+-    use libc;
+-
+     #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+     #[repr(i32)]
+     pub enum Errno {
+@@ -1101,8 +1155,6 @@ mod consts {
+ 
+ #[cfg(target_os = "freebsd")]
+ mod consts {
+-    use libc;
+-
+     #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+     #[repr(i32)]
+     pub enum Errno {
+@@ -1319,8 +1371,6 @@ mod consts {
+ 
+ #[cfg(target_os = "dragonfly")]
+ mod consts {
+-    use libc;
+-
+     #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+     #[repr(i32)]
+     pub enum Errno {
+@@ -1534,8 +1584,6 @@ mod consts {
+ 
+ #[cfg(target_os = "openbsd")]
+ mod consts {
+-    use libc;
+-
+     #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+     #[repr(i32)]
+     pub enum Errno {
+@@ -1748,8 +1796,6 @@ mod consts {
+ 
+ #[cfg(target_os = "netbsd")]
+ mod consts {
+-    use libc;
+-
+     #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+     #[repr(i32)]
+     pub enum Errno {
+@@ -1961,3 +2007,195 @@ mod consts {
+         }
+     }
+ }
++
++#[cfg(target_os = "redox")]
++mod consts {
++    #[derive(Clone, Copy, Debug, Eq, PartialEq)]
++    #[repr(i32)]
++    pub enum Errno {
++        UnknownErrno = 0,
++        EPERM = libc::EPERM,
++        ENOENT = libc::ENOENT,
++        ESRCH = libc::ESRCH,
++        EINTR = libc::EINTR,
++        EIO = libc::EIO,
++        ENXIO = libc::ENXIO,
++        E2BIG = libc::E2BIG,
++        ENOEXEC = libc::ENOEXEC,
++        EBADF = libc::EBADF,
++        ECHILD = libc::ECHILD,
++        EDEADLK = libc::EDEADLK,
++        ENOMEM = libc::ENOMEM,
++        EACCES = libc::EACCES,
++        EFAULT = libc::EFAULT,
++        ENOTBLK = libc::ENOTBLK,
++        EBUSY = libc::EBUSY,
++        EEXIST = libc::EEXIST,
++        EXDEV = libc::EXDEV,
++        ENODEV = libc::ENODEV,
++        ENOTDIR = libc::ENOTDIR,
++        EISDIR = libc::EISDIR,
++        EINVAL = libc::EINVAL,
++        ENFILE = libc::ENFILE,
++        EMFILE = libc::EMFILE,
++        ENOTTY = libc::ENOTTY,
++        ETXTBSY = libc::ETXTBSY,
++        EFBIG = libc::EFBIG,
++        ENOSPC = libc::ENOSPC,
++        ESPIPE = libc::ESPIPE,
++        EROFS = libc::EROFS,
++        EMLINK = libc::EMLINK,
++        EPIPE = libc::EPIPE,
++        EDOM = libc::EDOM,
++        ERANGE = libc::ERANGE,
++        EAGAIN = libc::EAGAIN,
++        EINPROGRESS = libc::EINPROGRESS,
++        EALREADY = libc::EALREADY,
++        ENOTSOCK = libc::ENOTSOCK,
++        EDESTADDRREQ = libc::EDESTADDRREQ,
++        EMSGSIZE = libc::EMSGSIZE,
++        EPROTOTYPE = libc::EPROTOTYPE,
++        ENOPROTOOPT = libc::ENOPROTOOPT,
++        EPROTONOSUPPORT = libc::EPROTONOSUPPORT,
++        ESOCKTNOSUPPORT = libc::ESOCKTNOSUPPORT,
++        EOPNOTSUPP = libc::EOPNOTSUPP,
++        EPFNOSUPPORT = libc::EPFNOSUPPORT,
++        EAFNOSUPPORT = libc::EAFNOSUPPORT,
++        EADDRINUSE = libc::EADDRINUSE,
++        EADDRNOTAVAIL = libc::EADDRNOTAVAIL,
++        ENETDOWN = libc::ENETDOWN,
++        ENETUNREACH = libc::ENETUNREACH,
++        ENETRESET = libc::ENETRESET,
++        ECONNABORTED = libc::ECONNABORTED,
++        ECONNRESET = libc::ECONNRESET,
++        ENOBUFS = libc::ENOBUFS,
++        EISCONN = libc::EISCONN,
++        ENOTCONN = libc::ENOTCONN,
++        ESHUTDOWN = libc::ESHUTDOWN,
++        ETOOMANYREFS = libc::ETOOMANYREFS,
++        ETIMEDOUT = libc::ETIMEDOUT,
++        ECONNREFUSED = libc::ECONNREFUSED,
++        ELOOP = libc::ELOOP,
++        ENAMETOOLONG = libc::ENAMETOOLONG,
++        EHOSTDOWN = libc::EHOSTDOWN,
++        EHOSTUNREACH = libc::EHOSTUNREACH,
++        ENOTEMPTY = libc::ENOTEMPTY,
++        EUSERS = libc::EUSERS,
++        EDQUOT = libc::EDQUOT,
++        ESTALE = libc::ESTALE,
++        EREMOTE = libc::EREMOTE,
++        ENOLCK = libc::ENOLCK,
++        ENOSYS = libc::ENOSYS,
++        EIDRM = libc::EIDRM,
++        ENOMSG = libc::ENOMSG,
++        EOVERFLOW = libc::EOVERFLOW,
++        EILSEQ = libc::EILSEQ,
++        ECANCELED = libc::ECANCELED,
++        EBADMSG = libc::EBADMSG,
++        ENODATA = libc::ENODATA,
++        ENOSR = libc::ENOSR,
++        ENOSTR = libc::ENOSTR,
++        ETIME = libc::ETIME,
++        EMULTIHOP = libc::EMULTIHOP,
++        ENOLINK = libc::ENOLINK,
++        EPROTO = libc::EPROTO,
++    }
++
++    pub const ELAST: Errno = Errno::UnknownErrno;
++    pub const EWOULDBLOCK: Errno = Errno::EAGAIN;
++
++    pub const EL2NSYNC: Errno = Errno::UnknownErrno;
++
++    pub fn from_i32(e: i32) -> Errno {
++        use self::Errno::*;
++
++        match e {
++            libc::EPERM => EPERM,
++            libc::ENOENT => ENOENT,
++            libc::ESRCH => ESRCH,
++            libc::EINTR => EINTR,
++            libc::EIO => EIO,
++            libc::ENXIO => ENXIO,
++            libc::E2BIG => E2BIG,
++            libc::ENOEXEC => ENOEXEC,
++            libc::EBADF => EBADF,
++            libc::ECHILD => ECHILD,
++            libc::EDEADLK => EDEADLK,
++            libc::ENOMEM => ENOMEM,
++            libc::EACCES => EACCES,
++            libc::EFAULT => EFAULT,
++            libc::ENOTBLK => ENOTBLK,
++            libc::EBUSY => EBUSY,
++            libc::EEXIST => EEXIST,
++            libc::EXDEV => EXDEV,
++            libc::ENODEV => ENODEV,
++            libc::ENOTDIR => ENOTDIR,
++            libc::EISDIR => EISDIR,
++            libc::EINVAL => EINVAL,
++            libc::ENFILE => ENFILE,
++            libc::EMFILE => EMFILE,
++            libc::ENOTTY => ENOTTY,
++            libc::ETXTBSY => ETXTBSY,
++            libc::EFBIG => EFBIG,
++            libc::ENOSPC => ENOSPC,
++            libc::ESPIPE => ESPIPE,
++            libc::EROFS => EROFS,
++            libc::EMLINK => EMLINK,
++            libc::EPIPE => EPIPE,
++            libc::EDOM => EDOM,
++            libc::ERANGE => ERANGE,
++            libc::EAGAIN => EAGAIN,
++            libc::EINPROGRESS => EINPROGRESS,
++            libc::EALREADY => EALREADY,
++            libc::ENOTSOCK => ENOTSOCK,
++            libc::EDESTADDRREQ => EDESTADDRREQ,
++            libc::EMSGSIZE => EMSGSIZE,
++            libc::EPROTOTYPE => EPROTOTYPE,
++            libc::ENOPROTOOPT => ENOPROTOOPT,
++            libc::EPROTONOSUPPORT => EPROTONOSUPPORT,
++            libc::ESOCKTNOSUPPORT => ESOCKTNOSUPPORT,
++            libc::EOPNOTSUPP => EOPNOTSUPP,
++            libc::EPFNOSUPPORT => EPFNOSUPPORT,
++            libc::EAFNOSUPPORT => EAFNOSUPPORT,
++            libc::EADDRINUSE => EADDRINUSE,
++            libc::EADDRNOTAVAIL => EADDRNOTAVAIL,
++            libc::ENETDOWN => ENETDOWN,
++            libc::ENETUNREACH => ENETUNREACH,
++            libc::ENETRESET => ENETRESET,
++            libc::ECONNABORTED => ECONNABORTED,
++            libc::ECONNRESET => ECONNRESET,
++            libc::ENOBUFS => ENOBUFS,
++            libc::EISCONN => EISCONN,
++            libc::ENOTCONN => ENOTCONN,
++            libc::ESHUTDOWN => ESHUTDOWN,
++            libc::ETOOMANYREFS => ETOOMANYREFS,
++            libc::ETIMEDOUT => ETIMEDOUT,
++            libc::ECONNREFUSED => ECONNREFUSED,
++            libc::ELOOP => ELOOP,
++            libc::ENAMETOOLONG => ENAMETOOLONG,
++            libc::EHOSTDOWN => EHOSTDOWN,
++            libc::EHOSTUNREACH => EHOSTUNREACH,
++            libc::ENOTEMPTY => ENOTEMPTY,
++            libc::EUSERS => EUSERS,
++            libc::EDQUOT => EDQUOT,
++            libc::ESTALE => ESTALE,
++            libc::EREMOTE => EREMOTE,
++            libc::ENOLCK => ENOLCK,
++            libc::ENOSYS => ENOSYS,
++            libc::EIDRM => EIDRM,
++            libc::ENOMSG => ENOMSG,
++            libc::EOVERFLOW => EOVERFLOW,
++            libc::EILSEQ => EILSEQ,
++            libc::ECANCELED => ECANCELED,
++            libc::EBADMSG => EBADMSG,
++            libc::ENODATA => ENODATA,
++            libc::ENOSR => ENOSR,
++            libc::ENOSTR => ENOSTR,
++            libc::ETIME => ETIME,
++            libc::EMULTIHOP => EMULTIHOP,
++            libc::ENOLINK => ENOLINK,
++            libc::EPROTO => EPROTO,
++            _ => UnknownErrno,
++        }
++    }
++}
+diff --git a/third_party/rust/nix/src/fcntl.rs b/third_party/rust/nix/src/fcntl.rs
+index be6ee0f73a8be..d2242dacd61b0 100644
+--- a/third_party/rust/nix/src/fcntl.rs
++++ b/third_party/rust/nix/src/fcntl.rs
+@@ -1,29 +1,34 @@
+-use {Error, Result, NixPath};
+-use errno::Errno;
+-use libc::{self, c_int, c_uint, c_char, size_t, ssize_t};
+-use sys::stat::Mode;
++use crate::errno::Errno;
++use libc::{self, c_char, c_int, c_uint, size_t, ssize_t};
++use std::ffi::OsString;
++#[cfg(not(target_os = "redox"))]
+ use std::os::raw;
++use std::os::unix::ffi::OsStringExt;
+ use std::os::unix::io::RawFd;
+-use std::ffi::OsStr;
+-use std::os::unix::ffi::OsStrExt;
++use crate::sys::stat::Mode;
++use crate::{NixPath, Result};
+ 
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ use std::ptr; // For splice and copy_file_range
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+-use sys::uio::IoVec;  // For vmsplice
+-
+-#[cfg(any(target_os = "linux",
+-          target_os = "android",
+-          target_os = "emscripten",
+-          target_os = "fuchsia",
+-          any(target_os = "wasi", target_env = "wasi"),
+-          target_env = "uclibc",
+-          target_env = "freebsd"))]
++use crate::sys::uio::IoVec; // For vmsplice
++
++#[cfg(any(
++    target_os = "linux",
++    target_os = "android",
++    target_os = "emscripten",
++    target_os = "fuchsia",
++    any(target_os = "wasi", target_env = "wasi"),
++    target_env = "uclibc",
++    target_os = "freebsd"
++))]
+ pub use self::posix_fadvise::*;
+ 
+-libc_bitflags!{
++#[cfg(not(target_os = "redox"))]
++libc_bitflags! {
+     pub struct AtFlags: c_int {
+         AT_REMOVEDIR;
++        AT_SYMLINK_FOLLOW;
+         AT_SYMLINK_NOFOLLOW;
+         #[cfg(any(target_os = "android", target_os = "linux"))]
+         AT_NO_AUTOMOUNT;
+@@ -78,7 +83,8 @@ libc_bitflags!(
+                   target_os = "ios",
+                   target_os = "macos",
+                   target_os = "netbsd",
+-                  target_os = "openbsd"))]
++                  target_os = "openbsd",
++                  target_os = "redox"))]
+         O_EXLOCK;
+         /// Same as `O_SYNC`.
+         #[cfg(any(target_os = "dragonfly",
+@@ -87,7 +93,8 @@ libc_bitflags!(
+                   all(target_os = "linux", not(target_env = "musl")),
+                   target_os = "macos",
+                   target_os = "netbsd",
+-                  target_os = "openbsd"))]
++                  target_os = "openbsd",
++                  target_os = "redox"))]
+         O_FSYNC;
+         /// Allow files whose sizes can't be represented in an `off_t` to be opened.
+         #[cfg(any(target_os = "android", target_os = "linux"))]
+@@ -96,8 +103,10 @@ libc_bitflags!(
+         #[cfg(any(target_os = "android", target_os = "linux"))]
+         O_NOATIME;
+         /// Don't attach the device as the process' controlling terminal.
++        #[cfg(not(target_os = "redox"))]
+         O_NOCTTY;
+         /// Same as `O_NONBLOCK`.
++        #[cfg(not(target_os = "redox"))]
+         O_NDELAY;
+         /// `open()` will fail if the given path is a symbolic link.
+         O_NOFOLLOW;
+@@ -109,7 +118,7 @@ libc_bitflags!(
+         /// Obtain a file descriptor for low-level access.
+         ///
+         /// The file itself is not opened and other file operations will fail.
+-        #[cfg(any(target_os = "android", target_os = "linux"))]
++        #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
+         O_PATH;
+         /// Only allow reading.
+         ///
+@@ -131,9 +140,11 @@ libc_bitflags!(
+                   target_os = "ios",
+                   target_os = "macos",
+                   target_os = "netbsd",
+-                  target_os = "openbsd"))]
++                  target_os = "openbsd",
++                  target_os = "redox"))]
+         O_SHLOCK;
+         /// Implicitly follow each `write()` with an `fsync()`.
++        #[cfg(not(target_os = "redox"))]
+         O_SYNC;
+         /// Create an unnamed temporary file.
+         #[cfg(any(target_os = "android", target_os = "linux"))]
+@@ -150,6 +161,8 @@ libc_bitflags!(
+     }
+ );
+ 
++// The conversion is not identical on all operating systems.
++#[allow(clippy::identity_conversion)]
+ pub fn open<P: ?Sized + NixPath>(path: &P, oflag: OFlag, mode: Mode) -> Result<RawFd> {
+     let fd = path.with_nix_path(|cstr| {
+         unsafe { libc::open(cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) }
+@@ -158,56 +171,125 @@ pub fn open<P: ?Sized + NixPath>(path: &P, oflag: OFlag, mode: Mode) -> Result<R
+     Errno::result(fd)
+ }
+ 
+-pub fn openat<P: ?Sized + NixPath>(dirfd: RawFd, path: &P, oflag: OFlag, mode: Mode) -> Result<RawFd> {
++// The conversion is not identical on all operating systems.
++#[allow(clippy::identity_conversion)]
++#[cfg(not(target_os = "redox"))]
++pub fn openat<P: ?Sized + NixPath>(
++    dirfd: RawFd,
++    path: &P,
++    oflag: OFlag,
++    mode: Mode,
++) -> Result<RawFd> {
+     let fd = path.with_nix_path(|cstr| {
+         unsafe { libc::openat(dirfd, cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) }
+     })?;
+     Errno::result(fd)
+ }
+ 
+-pub fn renameat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(old_dirfd: Option<RawFd>, old_path: &P1,
+-                                                            new_dirfd: Option<RawFd>, new_path: &P2)
+-                                                            -> Result<()> {
++#[cfg(not(target_os = "redox"))]
++pub fn renameat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
++    old_dirfd: Option<RawFd>,
++    old_path: &P1,
++    new_dirfd: Option<RawFd>,
++    new_path: &P2,
++) -> Result<()> {
+     let res = old_path.with_nix_path(|old_cstr| {
+         new_path.with_nix_path(|new_cstr| unsafe {
+-            libc::renameat(at_rawfd(old_dirfd), old_cstr.as_ptr(),
+-                           at_rawfd(new_dirfd), new_cstr.as_ptr())
++            libc::renameat(
++                at_rawfd(old_dirfd),
++                old_cstr.as_ptr(),
++                at_rawfd(new_dirfd),
++                new_cstr.as_ptr(),
++            )
+         })
+     })??;
+     Errno::result(res).map(drop)
+ }
+ 
+-fn wrap_readlink_result(buffer: &mut[u8], res: ssize_t) -> Result<&OsStr> {
+-    match Errno::result(res) {
+-        Err(err) => Err(err),
+-        Ok(len) => {
+-            if (len as usize) >= buffer.len() {
+-                Err(Error::Sys(Errno::ENAMETOOLONG))
+-            } else {
+-                Ok(OsStr::from_bytes(&buffer[..(len as usize)]))
++fn wrap_readlink_result(mut v: Vec<u8>, len: ssize_t) -> Result<OsString> {
++    unsafe { v.set_len(len as usize) }
++    v.shrink_to_fit();
++    Ok(OsString::from_vec(v.to_vec()))
++}
++
++fn readlink_maybe_at<P: ?Sized + NixPath>(
++    dirfd: Option<RawFd>,
++    path: &P,
++    v: &mut Vec<u8>,
++) -> Result<libc::ssize_t> {
++    path.with_nix_path(|cstr| unsafe {
++        match dirfd {
++            #[cfg(target_os = "redox")]
++            Some(_) => unreachable!(),
++            #[cfg(not(target_os = "redox"))]
++            Some(dirfd) => libc::readlinkat(
++                dirfd,
++                cstr.as_ptr(),
++                v.as_mut_ptr() as *mut c_char,
++                v.capacity() as size_t,
++            ),
++            None => libc::readlink(
++                cstr.as_ptr(),
++                v.as_mut_ptr() as *mut c_char,
++                v.capacity() as size_t,
++            ),
++        }
++    })
++}
++
++fn inner_readlink<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P) -> Result<OsString> {
++    let mut v = Vec::with_capacity(libc::PATH_MAX as usize);
++    // simple case: result is strictly less than `PATH_MAX`
++    let res = readlink_maybe_at(dirfd, path, &mut v)?;
++    let len = Errno::result(res)?;
++    debug_assert!(len >= 0);
++    if (len as usize) < v.capacity() {
++        return wrap_readlink_result(v, res);
++    }
++    // Uh oh, the result is too long...
++    // Let's try to ask lstat how many bytes to allocate.
++    let reported_size = super::sys::stat::lstat(path)
++        .and_then(|x| Ok(x.st_size))
++        .unwrap_or(0);
++    let mut try_size = if reported_size > 0 {
++        // Note: even if `lstat`'s apparently valid answer turns out to be
++        // wrong, we will still read the full symlink no matter what.
++        reported_size as usize + 1
++    } else {
++        // If lstat doesn't cooperate, or reports an error, be a little less
++        // precise.
++        (libc::PATH_MAX as usize).max(128) << 1
++    };
++    loop {
++        v.reserve_exact(try_size);
++        let res = readlink_maybe_at(dirfd, path, &mut v)?;
++        let len = Errno::result(res)?;
++        debug_assert!(len >= 0);
++        if (len as usize) < v.capacity() {
++            break wrap_readlink_result(v, res);
++        } else {
++            // Ugh! Still not big enough!
++            match try_size.checked_shl(1) {
++                Some(next_size) => try_size = next_size,
++                // It's absurd that this would happen, but handle it sanely
++                // anyway.
++                None => break Err(super::Error::Sys(Errno::ENAMETOOLONG)),
+             }
+         }
+     }
+ }
+ 
+-pub fn readlink<'a, P: ?Sized + NixPath>(path: &P, buffer: &'a mut [u8]) -> Result<&'a OsStr> {
+-    let res = path.with_nix_path(|cstr| {
+-        unsafe { libc::readlink(cstr.as_ptr(), buffer.as_mut_ptr() as *mut c_char, buffer.len() as size_t) }
+-    })?;
+-
+-    wrap_readlink_result(buffer, res)
++pub fn readlink<P: ?Sized + NixPath>(path: &P) -> Result<OsString> {
++    inner_readlink(None, path)
+ }
+ 
+-
+-pub fn readlinkat<'a, P: ?Sized + NixPath>(dirfd: RawFd, path: &P, buffer: &'a mut [u8]) -> Result<&'a OsStr> {
+-    let res = path.with_nix_path(|cstr| {
+-        unsafe { libc::readlinkat(dirfd, cstr.as_ptr(), buffer.as_mut_ptr() as *mut c_char, buffer.len() as size_t) }
+-    })?;
+-
+-    wrap_readlink_result(buffer, res)
++#[cfg(not(target_os = "redox"))]
++pub fn readlinkat<P: ?Sized + NixPath>(dirfd: RawFd, path: &P) -> Result<OsString> {
++    inner_readlink(Some(dirfd), path)
+ }
+ 
+ /// Computes the raw fd consumed by a function of the form `*at`.
++#[cfg(not(target_os = "redox"))]
+ pub(crate) fn at_rawfd(fd: Option<RawFd>) -> raw::c_int {
+     match fd {
+         None => libc::AT_FDCWD,
+@@ -238,6 +320,7 @@ libc_bitflags!(
+     }
+ );
+ 
++#[cfg(not(target_os = "redox"))]
+ #[derive(Debug, Eq, Hash, PartialEq)]
+ pub enum FcntlArg<'a> {
+     F_DUPFD(RawFd),
+@@ -265,9 +348,19 @@ pub enum FcntlArg<'a> {
+     F_GETPIPE_SZ,
+     #[cfg(any(target_os = "linux", target_os = "android"))]
+     F_SETPIPE_SZ(c_int),
+-
+     // TODO: Rest of flags
+ }
++
++#[cfg(target_os = "redox")]
++#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
++pub enum FcntlArg {
++    F_DUPFD(RawFd),
++    F_DUPFD_CLOEXEC(RawFd),
++    F_GETFD,
++    F_SETFD(FdFlag), // FD_FLAGS
++    F_GETFL,
++    F_SETFL(OFlag), // O_NONBLOCK
++}
+ pub use self::FcntlArg::*;
+ 
+ // TODO: Figure out how to handle value fcntl returns
+@@ -280,10 +373,19 @@ pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int> {
+             F_SETFD(flag) => libc::fcntl(fd, libc::F_SETFD, flag.bits()),
+             F_GETFL => libc::fcntl(fd, libc::F_GETFL),
+             F_SETFL(flag) => libc::fcntl(fd, libc::F_SETFL, flag.bits()),
++            #[cfg(not(target_os = "redox"))]
+             F_SETLK(flock) => libc::fcntl(fd, libc::F_SETLK, flock),
++            #[cfg(not(target_os = "redox"))]
+             F_SETLKW(flock) => libc::fcntl(fd, libc::F_SETLKW, flock),
++            #[cfg(not(target_os = "redox"))]
+             F_GETLK(flock) => libc::fcntl(fd, libc::F_GETLK, flock),
+             #[cfg(any(target_os = "android", target_os = "linux"))]
++            F_OFD_SETLK(flock) => libc::fcntl(fd, libc::F_OFD_SETLK, flock),
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            F_OFD_SETLKW(flock) => libc::fcntl(fd, libc::F_OFD_SETLKW, flock),
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            F_OFD_GETLK(flock) => libc::fcntl(fd, libc::F_OFD_GETLK, flock),
++            #[cfg(any(target_os = "android", target_os = "linux"))]
+             F_ADD_SEALS(flag) => libc::fcntl(fd, libc::F_ADD_SEALS, flag.bits()),
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+             F_GET_SEALS => libc::fcntl(fd, libc::F_GET_SEALS),
+@@ -293,8 +395,6 @@ pub fn fcntl(fd: RawFd, arg: FcntlArg) -> Result<c_int> {
+             F_GETPIPE_SZ => libc::fcntl(fd, libc::F_GETPIPE_SZ),
+             #[cfg(any(target_os = "linux", target_os = "android"))]
+             F_SETPIPE_SZ(size) => libc::fcntl(fd, libc::F_SETPIPE_SZ, size),
+-            #[cfg(any(target_os = "linux", target_os = "android"))]
+-            _ => unimplemented!()
+         }
+     };
+ 
+@@ -311,6 +411,7 @@ pub enum FlockArg {
+     UnlockNonblock,
+ }
+ 
++#[cfg(not(target_os = "redox"))]
+ pub fn flock(fd: RawFd, arg: FlockArg) -> Result<()> {
+     use self::FlockArg::*;
+ 
+@@ -410,9 +511,7 @@ pub fn splice(
+         .map(|offset| offset as *mut libc::loff_t)
+         .unwrap_or(ptr::null_mut());
+ 
+-    let ret = unsafe {
+-        libc::splice(fd_in, off_in, fd_out, off_out, len, flags.bits())
+-    };
++    let ret = unsafe { libc::splice(fd_in, off_in, fd_out, off_out, len, flags.bits()) };
+     Errno::result(ret).map(|r| r as usize)
+ }
+ 
+@@ -425,7 +524,12 @@ pub fn tee(fd_in: RawFd, fd_out: RawFd, len: usize, flags: SpliceFFlags) -> Resu
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ pub fn vmsplice(fd: RawFd, iov: &[IoVec<&[u8]>], flags: SpliceFFlags) -> Result<usize> {
+     let ret = unsafe {
+-        libc::vmsplice(fd, iov.as_ptr() as *const libc::iovec, iov.len(), flags.bits())
++        libc::vmsplice(
++            fd,
++            iov.as_ptr() as *const libc::iovec,
++            iov.len(),
++            flags.bits(),
++        )
+     };
+     Errno::result(ret).map(|r| r as usize)
+ }
+@@ -466,23 +570,30 @@ libc_bitflags!(
+ /// Allows the caller to directly manipulate the allocated disk space for the
+ /// file referred to by fd.
+ #[cfg(any(target_os = "linux"))]
+-pub fn fallocate(fd: RawFd, mode: FallocateFlags, offset: libc::off_t, len: libc::off_t) -> Result<c_int> {
++pub fn fallocate(
++    fd: RawFd,
++    mode: FallocateFlags,
++    offset: libc::off_t,
++    len: libc::off_t,
++) -> Result<()> {
+     let res = unsafe { libc::fallocate(fd, mode.bits(), offset, len) };
+-    Errno::result(res)
++    Errno::result(res).map(drop)
+ }
+ 
+-#[cfg(any(target_os = "linux",
+-          target_os = "android",
+-          target_os = "emscripten",
+-          target_os = "fuchsia",
+-          any(target_os = "wasi", target_env = "wasi"),
+-          target_env = "uclibc",
+-          target_env = "freebsd"))]
++#[cfg(any(
++    target_os = "linux",
++    target_os = "android",
++    target_os = "emscripten",
++    target_os = "fuchsia",
++    any(target_os = "wasi", target_env = "wasi"),
++    target_env = "uclibc",
++    target_os = "freebsd"
++))]
+ mod posix_fadvise {
+-    use Result;
++    use crate::errno::Errno;
+     use libc;
+-    use errno::Errno;
+     use std::os::unix::io::RawFd;
++    use crate::Result;
+ 
+     libc_enum! {
+         #[repr(i32)]
+@@ -496,11 +607,30 @@ mod posix_fadvise {
+         }
+     }
+ 
+-    pub fn posix_fadvise(fd: RawFd,
+-                         offset: libc::off_t,
+-                         len: libc::off_t,
+-                         advice: PosixFadviseAdvice) -> Result<libc::c_int> {
++    pub fn posix_fadvise(
++        fd: RawFd,
++        offset: libc::off_t,
++        len: libc::off_t,
++        advice: PosixFadviseAdvice,
++    ) -> Result<libc::c_int> {
+         let res = unsafe { libc::posix_fadvise(fd, offset, len, advice as libc::c_int) };
+         Errno::result(res)
+     }
+ }
++
++#[cfg(any(
++    target_os = "linux",
++    target_os = "android",
++    target_os = "emscripten",
++    target_os = "fuchsia",
++    any(target_os = "wasi", target_env = "wasi"),
++    target_os = "freebsd"
++))]
++pub fn posix_fallocate(fd: RawFd, offset: libc::off_t, len: libc::off_t) -> Result<()> {
++    let res = unsafe { libc::posix_fallocate(fd, offset, len) };
++    match Errno::result(res) {
++        Err(err) => Err(err),
++        Ok(0) => Ok(()),
++        Ok(errno) => Err(crate::Error::Sys(Errno::from_i32(errno))),
++    }
++}
+diff --git a/third_party/rust/nix/src/features.rs b/third_party/rust/nix/src/features.rs
+index 76cdfd3a1a6f1..6b1cff5deed1d 100644
+--- a/third_party/rust/nix/src/features.rs
++++ b/third_party/rust/nix/src/features.rs
+@@ -3,7 +3,7 @@ pub use self::os::*;
+ 
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ mod os {
+-    use sys::utsname::uname;
++    use crate::sys::utsname::uname;
+ 
+     // Features:
+     // * atomic cloexec on socket: 2.6.27
+@@ -94,7 +94,10 @@ mod os {
+     }
+ }
+ 
+-#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "dragonfly", target_os = "ios", target_os = "openbsd", target_os = "netbsd"))]
++#[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 = "fuchsia"))]
+ mod os {
+     /// Check if the OS supports atomic close-on-exec for sockets
+     pub fn socket_atomic_cloexec() -> bool {
+diff --git a/third_party/rust/nix/src/ifaddrs.rs b/third_party/rust/nix/src/ifaddrs.rs
+index 12b59bcc92bef..ed6328f3efab2 100644
+--- a/third_party/rust/nix/src/ifaddrs.rs
++++ b/third_party/rust/nix/src/ifaddrs.rs
+@@ -3,16 +3,15 @@
+ //! Uses the Linux and/or BSD specific function `getifaddrs` to query the list
+ //! of interfaces and their associated addresses.
+ 
++use cfg_if::cfg_if;
+ use std::ffi;
+ use std::iter::Iterator;
+ use std::mem;
+ use std::option::Option;
+ 
+-use libc;
+-
+-use {Result, Errno};
+-use sys::socket::SockAddr;
+-use net::if_::*;
++use crate::{Result, Errno};
++use crate::sys::socket::SockAddr;
++use crate::net::if_::*;
+ 
+ /// Describes a single address for an interface as returned by `getifaddrs`.
+ #[derive(Clone, Debug, Eq, Hash, PartialEq)]
+@@ -52,8 +51,8 @@ impl InterfaceAddress {
+         let mut addr = InterfaceAddress {
+             interface_name: ifname.to_string_lossy().to_string(),
+             flags: InterfaceFlags::from_bits_truncate(info.ifa_flags as i32),
+-            address: address,
+-            netmask: netmask,
++            address,
++            netmask,
+             broadcast: None,
+             destination: None,
+         };
+@@ -125,13 +124,15 @@ impl Iterator for InterfaceAddressIterator {
+ /// }
+ /// ```
+ pub fn getifaddrs() -> Result<InterfaceAddressIterator> {
+-    let mut addrs: *mut libc::ifaddrs = unsafe { mem::uninitialized() };
+-    Errno::result(unsafe { libc::getifaddrs(&mut addrs) }).map(|_| {
+-        InterfaceAddressIterator {
+-            base: addrs,
+-            next: addrs,
+-        }
+-    })
++    let mut addrs = mem::MaybeUninit::<*mut libc::ifaddrs>::uninit();
++    unsafe {
++        Errno::result(libc::getifaddrs(addrs.as_mut_ptr())).map(|_| {
++            InterfaceAddressIterator {
++                base: addrs.assume_init(),
++                next: addrs.assume_init(),
++            }
++        })
++    }
+ }
+ 
+ #[cfg(test)]
+diff --git a/third_party/rust/nix/src/kmod.rs b/third_party/rust/nix/src/kmod.rs
+index e853261b14f9d..8789cb69f4617 100644
+--- a/third_party/rust/nix/src/kmod.rs
++++ b/third_party/rust/nix/src/kmod.rs
+@@ -6,8 +6,8 @@ use libc;
+ use std::ffi::CStr;
+ use std::os::unix::io::AsRawFd;
+ 
+-use errno::Errno;
+-use Result;
++use crate::errno::Errno;
++use crate::Result;
+ 
+ /// Loads a kernel module from a buffer.
+ ///
+diff --git a/third_party/rust/nix/src/lib.rs b/third_party/rust/nix/src/lib.rs
+index 71485d2af1824..e62c158c8bc9b 100644
+--- a/third_party/rust/nix/src/lib.rs
++++ b/third_party/rust/nix/src/lib.rs
+@@ -14,24 +14,17 @@
+ #![deny(unstable_features)]
+ #![deny(missing_copy_implementations)]
+ #![deny(missing_debug_implementations)]
+-// XXX Allow deprecated items until release 0.16.0.  See issue #1096.
+-#![allow(deprecated)]
+-
+-// External crates
+-#[macro_use]
+-extern crate bitflags;
+-#[macro_use]
+-extern crate cfg_if;
+-extern crate void;
+ 
+ // Re-exported external crates
+-pub extern crate libc;
++pub use libc;
+ 
+ // Private internal modules
+ #[macro_use] mod macros;
+ 
+ // Public crates
++#[cfg(not(target_os = "redox"))]
+ pub mod dir;
++pub mod env;
+ pub mod errno;
+ #[deny(missing_docs)]
+ pub mod features;
+@@ -59,13 +52,16 @@ pub mod mount;
+           target_os = "netbsd"))]
+ pub mod mqueue;
+ #[deny(missing_docs)]
++#[cfg(not(target_os = "redox"))]
+ pub mod net;
+ #[deny(missing_docs)]
+ pub mod poll;
+ #[deny(missing_docs)]
++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
+ pub mod pty;
+ pub mod sched;
+ pub mod sys;
++pub mod time;
+ // This can be implemented for other platforms as soon as libc
+ // provides bindings for them.
+ #[cfg(all(target_os = "linux",
+@@ -121,9 +117,9 @@ impl Error {
+     /// let e = Error::from(Errno::EPERM);
+     /// assert_eq!(Some(Errno::EPERM), e.as_errno());
+     /// ```
+-    pub fn as_errno(&self) -> Option<Errno> {
+-        if let &Error::Sys(ref e) = self {
+-            Some(*e)
++    pub fn as_errno(self) -> Option<Errno> {
++        if let Error::Sys(e) = self {
++            Some(e)
+         } else {
+             None
+         }
+@@ -154,16 +150,7 @@ impl From<std::string::FromUtf8Error> for Error {
+     fn from(_: std::string::FromUtf8Error) -> Error { Error::InvalidUtf8 }
+ }
+ 
+-impl error::Error for Error {
+-    fn description(&self) -> &str {
+-        match *self {
+-            Error::InvalidPath => "Invalid path",
+-            Error::InvalidUtf8 => "Invalid UTF-8 string",
+-            Error::UnsupportedOperation => "Unsupported Operation",
+-            Error::Sys(ref errno) => errno.desc(),
+-        }
+-    }
+-}
++impl error::Error for Error {}
+ 
+ impl fmt::Display for Error {
+     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+@@ -177,6 +164,8 @@ impl fmt::Display for Error {
+ }
+ 
+ pub trait NixPath {
++    fn is_empty(&self) -> bool;
++
+     fn len(&self) -> usize;
+ 
+     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
+@@ -184,6 +173,10 @@ pub trait NixPath {
+ }
+ 
+ impl NixPath for str {
++    fn is_empty(&self) -> bool {
++        NixPath::is_empty(OsStr::new(self))
++    }
++
+     fn len(&self) -> usize {
+         NixPath::len(OsStr::new(self))
+     }
+@@ -195,6 +188,10 @@ impl NixPath for str {
+ }
+ 
+ impl NixPath for OsStr {
++    fn is_empty(&self) -> bool {
++        self.as_bytes().is_empty()
++    }
++
+     fn len(&self) -> usize {
+         self.as_bytes().len()
+     }
+@@ -206,6 +203,10 @@ impl NixPath for OsStr {
+ }
+ 
+ impl NixPath for CStr {
++    fn is_empty(&self) -> bool {
++        self.to_bytes().is_empty()
++    }
++
+     fn len(&self) -> usize {
+         self.to_bytes().len()
+     }
+@@ -222,6 +223,10 @@ impl NixPath for CStr {
+ }
+ 
+ impl NixPath for [u8] {
++    fn is_empty(&self) -> bool {
++        self.is_empty()
++    }
++
+     fn len(&self) -> usize {
+         self.len()
+     }
+@@ -249,6 +254,10 @@ impl NixPath for [u8] {
+ }
+ 
+ impl NixPath for Path {
++    fn is_empty(&self) -> bool {
++        NixPath::is_empty(self.as_os_str())
++    }
++
+     fn len(&self) -> usize {
+         NixPath::len(self.as_os_str())
+     }
+@@ -259,26 +268,15 @@ impl NixPath for Path {
+ }
+ 
+ impl NixPath for PathBuf {
+-    fn len(&self) -> usize {
+-        NixPath::len(self.as_os_str())
++    fn is_empty(&self) -> bool {
++        NixPath::is_empty(self.as_os_str())
+     }
+ 
+-    fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
+-        self.as_os_str().with_nix_path(f)
+-    }
+-}
+-
+-/// Treats `None` as an empty string.
+-impl<'a, NP: ?Sized + NixPath>  NixPath for Option<&'a NP> {
+     fn len(&self) -> usize {
+-        self.map_or(0, NixPath::len)
++        NixPath::len(self.as_os_str())
+     }
+ 
+     fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
+-        if let Some(nix_path) = *self {
+-            nix_path.with_nix_path(f)
+-        } else {
+-            unsafe { CStr::from_ptr("\0".as_ptr() as *const _).with_nix_path(f) }
+-        }
++        self.as_os_str().with_nix_path(f)
+     }
+ }
+diff --git a/third_party/rust/nix/src/macros.rs b/third_party/rust/nix/src/macros.rs
+index 3d1b0e4b7699c..7d6ac8dfbf5f7 100644
+--- a/third_party/rust/nix/src/macros.rs
++++ b/third_party/rust/nix/src/macros.rs
+@@ -48,7 +48,7 @@ macro_rules! libc_bitflags {
+             )+
+         }
+     ) => {
+-        bitflags! {
++        ::bitflags::bitflags! {
+             $(#[$outer])*
+             pub struct $BitFlags: $T {
+                 $(
+@@ -81,9 +81,10 @@ macro_rules! libc_bitflags {
+ /// }
+ /// ```
+ macro_rules! libc_enum {
+-    // (non-pub) Exit rule.
++    // Exit rule.
+     (@make_enum
+         {
++            $v:vis
+             name: $BitFlags:ident,
+             attrs: [$($attrs:tt)*],
+             entries: [$($entries:tt)*],
+@@ -91,49 +92,15 @@ macro_rules! libc_enum {
+     ) => {
+         $($attrs)*
+         #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+-        enum $BitFlags {
++        $v enum $BitFlags {
+             $($entries)*
+         }
+     };
+ 
+-    // (pub) Exit rule.
+-    (@make_enum
+-        {
+-            pub,
+-            name: $BitFlags:ident,
+-            attrs: [$($attrs:tt)*],
+-            entries: [$($entries:tt)*],
+-        }
+-    ) => {
+-        $($attrs)*
+-        #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+-        pub enum $BitFlags {
+-            $($entries)*
+-        }
+-    };
+-
+-    // (non-pub) Done accumulating.
+-    (@accumulate_entries
+-        {
+-            name: $BitFlags:ident,
+-            attrs: $attrs:tt,
+-        },
+-        $entries:tt;
+-    ) => {
+-        libc_enum! {
+-            @make_enum
+-            {
+-                name: $BitFlags,
+-                attrs: $attrs,
+-                entries: $entries,
+-            }
+-        }
+-    };
+-
+-    // (pub) Done accumulating.
++    // Done accumulating.
+     (@accumulate_entries
+         {
+-            pub,
++            $v:vis
+             name: $BitFlags:ident,
+             attrs: $attrs:tt,
+         },
+@@ -142,7 +109,7 @@ macro_rules! libc_enum {
+         libc_enum! {
+             @make_enum
+             {
+-                pub,
++                $v
+                 name: $BitFlags,
+                 attrs: $attrs,
+                 entries: $entries,
+@@ -217,35 +184,17 @@ macro_rules! libc_enum {
+         }
+     };
+ 
+-    // (non-pub) Entry rule.
+-    (
+-        $(#[$attr:meta])*
+-        enum $BitFlags:ident {
+-            $($vals:tt)*
+-        }
+-    ) => {
+-        libc_enum! {
+-            @accumulate_entries
+-            {
+-                name: $BitFlags,
+-                attrs: [$(#[$attr])*],
+-            },
+-            [];
+-            $($vals)*
+-        }
+-    };
+-
+-    // (pub) Entry rule.
++    // Entry rule.
+     (
+         $(#[$attr:meta])*
+-        pub enum $BitFlags:ident {
++        $v:vis enum $BitFlags:ident {
+             $($vals:tt)*
+         }
+     ) => {
+         libc_enum! {
+             @accumulate_entries
+             {
+-                pub,
++                $v
+                 name: $BitFlags,
+                 attrs: [$(#[$attr])*],
+             },
+@@ -254,11 +203,3 @@ macro_rules! libc_enum {
+         }
+     };
+ }
+-
+-/// A Rust version of the familiar C `offset_of` macro.  It returns the byte
+-/// offset of `field` within struct `ty`
+-macro_rules! offset_of {
+-    ($ty:ty, $field:ident) => {
+-        &(*(0 as *const $ty)).$field as *const _ as usize
+-    }
+-}
+diff --git a/third_party/rust/nix/src/mount.rs b/third_party/rust/nix/src/mount.rs
+index a9902b170ace8..2c54761e2bb0c 100644
+--- a/third_party/rust/nix/src/mount.rs
++++ b/third_party/rust/nix/src/mount.rs
+@@ -1,6 +1,6 @@
+ use libc::{self, c_ulong, c_int};
+-use {Result, NixPath};
+-use errno::Errno;
++use crate::{Result, NixPath};
++use crate::errno::Errno;
+ 
+ libc_bitflags!(
+     pub struct MsFlags: c_ulong {
+@@ -61,22 +61,33 @@ pub fn mount<P1: ?Sized + NixPath, P2: ?Sized + NixPath, P3: ?Sized + NixPath, P
+         flags: MsFlags,
+         data: Option<&P4>) -> Result<()> {
+ 
+-    let res =
+-        source.with_nix_path(|source| {
+-            target.with_nix_path(|target| {
+-                fstype.with_nix_path(|fstype| {
+-                    data.with_nix_path(|data| {
+-                        unsafe {
+-                            libc::mount(source.as_ptr(),
+-                                       target.as_ptr(),
+-                                       fstype.as_ptr(),
+-                                       flags.bits,
+-                                       data.as_ptr() as *const libc::c_void)
+-                        }
+-                    })
++    fn with_opt_nix_path<P, T, F>(p: Option<&P>, f: F) -> Result<T>
++        where P: ?Sized + NixPath,
++              F: FnOnce(*const libc::c_char) -> T
++    {
++        match p {
++            Some(path) => path.with_nix_path(|p_str| f(p_str.as_ptr())),
++            None => Ok(f(std::ptr::null()))
++        }
++    }
++
++    let res = with_opt_nix_path(source, |s| {
++        target.with_nix_path(|t| {
++            with_opt_nix_path(fstype, |ty| {
++                with_opt_nix_path(data, |d| {
++                    unsafe {
++                        libc::mount(
++                            s,
++                            t.as_ptr(),
++                            ty,
++                            flags.bits,
++                            d as *const libc::c_void
++                        )
++                    }
+                 })
+             })
+-        })????;
++        })
++    })????;
+ 
+     Errno::result(res).map(drop)
+ }
+diff --git a/third_party/rust/nix/src/mqueue.rs b/third_party/rust/nix/src/mqueue.rs
+index b958b71cddb46..0215de5af214b 100644
+--- a/third_party/rust/nix/src/mqueue.rs
++++ b/third_party/rust/nix/src/mqueue.rs
+@@ -2,12 +2,12 @@
+ //!
+ //! [Further reading and details on the C API](http://man7.org/linux/man-pages/man7/mq_overview.7.html)
+ 
+-use Result;
+-use errno::Errno;
++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 sys::stat::Mode;
++use crate::sys::stat::Mode;
+ use std::mem;
+ 
+ libc_bitflags!{
+@@ -34,21 +34,32 @@ pub struct MqAttr {
+     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)
+-               -> MqAttr {
+-        let mut attr = unsafe { mem::uninitialized::<libc::mq_attr>() };
+-        attr.mq_flags = mq_flags;
+-        attr.mq_maxmsg = mq_maxmsg;
+-        attr.mq_msgsize = mq_msgsize;
+-        attr.mq_curmsgs = mq_curmsgs;
+-        MqAttr { mq_attr: attr }
++    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();
++        unsafe {
++            let p = attr.as_mut_ptr();
++            (*p).mq_flags = mq_flags;
++            (*p).mq_maxmsg = mq_maxmsg;
++            (*p).mq_msgsize = mq_msgsize;
++            (*p).mq_curmsgs = mq_curmsgs;
++            MqAttr { mq_attr: attr.assume_init() }
++        }
+     }
+ 
+-    pub fn flags(&self) -> c_long {
++    pub fn flags(&self) -> mq_attr_member_t {
+         self.mq_attr.mq_flags
+     }
+ }
+@@ -57,6 +68,8 @@ impl MqAttr {
+ /// Open a message queue
+ ///
+ /// See also [`mq_open(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_open.html)
++// The mode.bits cast is only lossless on some OSes
++#[allow(clippy::cast_lossless)]
+ pub fn mq_open(name: &CString,
+                oflag: MQ_OFlag,
+                mode: Mode,
+@@ -121,9 +134,9 @@ pub fn mq_send(mqdes: mqd_t, message: &[u8], msq_prio: u32) -> Result<()> {
+ ///
+ /// See also [`mq_getattr(2)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_getattr.html)
+ pub fn mq_getattr(mqd: mqd_t) -> Result<MqAttr> {
+-    let mut attr = unsafe { mem::uninitialized::<libc::mq_attr>() };
+-    let res = unsafe { libc::mq_getattr(mqd, &mut attr) };
+-    Errno::result(res).map(|_| MqAttr { mq_attr: attr })
++    let mut attr = mem::MaybeUninit::<libc::mq_attr>::uninit();
++    let res = unsafe { libc::mq_getattr(mqd, attr.as_mut_ptr()) };
++    Errno::result(res).map(|_| unsafe{MqAttr { mq_attr: attr.assume_init() }})
+ }
+ 
+ /// Set the attributes of the message queue. Only `O_NONBLOCK` can be set, everything else will be ignored
+@@ -132,17 +145,19 @@ pub fn mq_getattr(mqd: mqd_t) -> Result<MqAttr> {
+ ///
+ /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_setattr.html)
+ pub fn mq_setattr(mqd: mqd_t, newattr: &MqAttr) -> Result<MqAttr> {
+-    let mut attr = unsafe { mem::uninitialized::<libc::mq_attr>() };
+-    let res = unsafe { libc::mq_setattr(mqd, &newattr.mq_attr as *const libc::mq_attr, &mut attr) };
+-    Errno::result(res).map(|_| MqAttr { mq_attr: attr })
++    let mut attr = mem::MaybeUninit::<libc::mq_attr>::uninit();
++    let res = unsafe {
++        libc::mq_setattr(mqd, &newattr.mq_attr as *const libc::mq_attr, attr.as_mut_ptr())
++    };
++    Errno::result(res).map(|_| unsafe{ MqAttr { mq_attr: attr.assume_init() }})
+ }
+ 
+ /// Convenience function.
+ /// Sets the `O_NONBLOCK` attribute for a given message queue descriptor
+ /// Returns the old attributes
+-pub fn mq_set_nonblock(mqd: mqd_t) -> Result<(MqAttr)> {
++pub fn mq_set_nonblock(mqd: mqd_t) -> Result<MqAttr> {
+     let oldattr = mq_getattr(mqd)?;
+-    let newattr = MqAttr::new(MQ_OFlag::O_NONBLOCK.bits() as c_long,
++    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);
+@@ -152,7 +167,7 @@ pub fn mq_set_nonblock(mqd: mqd_t) -> Result<(MqAttr)> {
+ /// Convenience function.
+ /// Removes `O_NONBLOCK` attribute for a given message queue descriptor
+ /// Returns the old attributes
+-pub fn mq_remove_nonblock(mqd: mqd_t) -> Result<(MqAttr)> {
++pub fn mq_remove_nonblock(mqd: mqd_t) -> Result<MqAttr> {
+     let oldattr = mq_getattr(mqd)?;
+     let newattr = MqAttr::new(0,
+                               oldattr.mq_attr.mq_maxmsg,
+diff --git a/third_party/rust/nix/src/net/if_.rs b/third_party/rust/nix/src/net/if_.rs
+index 58d677ae343d1..96364884e39cb 100644
+--- a/third_party/rust/nix/src/net/if_.rs
++++ b/third_party/rust/nix/src/net/if_.rs
+@@ -3,9 +3,8 @@
+ //! Uses Linux and/or POSIX functions to resolve interface names like "eth0"
+ //! or "socan1" into device numbers.
+ 
+-use libc;
+ use libc::c_uint;
+-use {Result, Error, NixPath};
++use crate::{Result, Error, NixPath};
+ 
+ /// Resolve an interface into a interface number.
+ pub fn if_nametoindex<P: ?Sized + NixPath>(name: &P) -> Result<c_uint> {
+diff --git a/third_party/rust/nix/src/poll.rs b/third_party/rust/nix/src/poll.rs
+index c603611e3176f..be5bf224990f2 100644
+--- a/third_party/rust/nix/src/poll.rs
++++ b/third_party/rust/nix/src/poll.rs
+@@ -1,13 +1,12 @@
+ //! Wait for events to trigger on specific file descriptors
+ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
+-use sys::time::TimeSpec;
++use crate::sys::time::TimeSpec;
+ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
+-use sys::signal::SigSet;
++use crate::sys::signal::SigSet;
+ use std::os::unix::io::RawFd;
+ 
+-use libc;
+-use Result;
+-use errno::Errno;
++use crate::Result;
++use crate::errno::Errno;
+ 
+ /// This is a wrapper around `libc::pollfd`.
+ ///
+@@ -17,7 +16,7 @@ use errno::Errno;
+ ///
+ /// After a call to `poll` or `ppoll`, the events that occured can be
+ /// retrieved by calling [`revents()`](#method.revents) on the `PollFd`.
+-#[repr(C)]
++#[repr(transparent)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+ pub struct PollFd {
+     pollfd: libc::pollfd,
+@@ -29,7 +28,7 @@ impl PollFd {
+     pub fn new(fd: RawFd, events: PollFlags) -> PollFd {
+         PollFd {
+             pollfd: libc::pollfd {
+-                fd: fd,
++                fd,
+                 events: events.bits(),
+                 revents: PollFlags::empty().bits(),
+             },
+@@ -37,7 +36,7 @@ impl PollFd {
+     }
+ 
+     /// Returns the events that occured in the last call to `poll` or `ppoll`.
+-    pub fn revents(&self) -> Option<PollFlags> {
++    pub fn revents(self) -> Option<PollFlags> {
+         PollFlags::from_bits(self.pollfd.revents)
+     }
+ }
+@@ -64,12 +63,16 @@ libc_bitflags! {
+         /// `O_NONBLOCK` is set).
+         POLLOUT;
+         /// Equivalent to [`POLLIN`](constant.POLLIN.html)
++        #[cfg(not(target_os = "redox"))]
+         POLLRDNORM;
++        #[cfg(not(target_os = "redox"))]
+         /// Equivalent to [`POLLOUT`](constant.POLLOUT.html)
+         POLLWRNORM;
+         /// Priority band data can be read (generally unused on Linux).
++        #[cfg(not(target_os = "redox"))]
+         POLLRDBAND;
+         /// Priority data may be written.
++        #[cfg(not(target_os = "redox"))]
+         POLLWRBAND;
+         /// Error condition (only returned in
+         /// [`PollFd::revents`](struct.PollFd.html#method.revents);
+@@ -127,16 +130,16 @@ pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result<libc::c_int> {
+ /// ([`poll(2)`](http://man7.org/linux/man-pages/man2/poll.2.html))
+ ///
+ /// `ppoll` behaves like `poll`, but let you specify what signals may interrupt it
+-/// with the `sigmask` argument.
++/// with the `sigmask` argument. If you want `ppoll` to block indefinitely,
++/// specify `None` as `timeout` (it is like `timeout = -1` for `poll`).
+ ///
+ #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
+-pub fn ppoll(fds: &mut [PollFd], timeout: TimeSpec, sigmask: SigSet) -> Result<libc::c_int> {
+-
+-
++pub fn ppoll(fds: &mut [PollFd], timeout: Option<TimeSpec>, sigmask: SigSet) -> Result<libc::c_int> {
++    let timeout = timeout.as_ref().map_or(core::ptr::null(), |r| r.as_ref());
+     let res = unsafe {
+         libc::ppoll(fds.as_mut_ptr() as *mut libc::pollfd,
+                     fds.len() as libc::nfds_t,
+-                    timeout.as_ref(),
++                    timeout,
+                     sigmask.as_ref())
+     };
+     Errno::result(res)
+diff --git a/third_party/rust/nix/src/pty.rs b/third_party/rust/nix/src/pty.rs
+index db012d8158c53..d67518f4744f3 100644
+--- a/third_party/rust/nix/src/pty.rs
++++ b/third_party/rust/nix/src/pty.rs
+@@ -1,18 +1,17 @@
+ //! Create master and slave virtual pseudo-terminals (PTYs)
+ 
+-use libc;
+-
+ pub use libc::pid_t as SessionId;
+ pub use libc::winsize as Winsize;
+ 
+ use std::ffi::CStr;
++use std::io;
+ use std::mem;
+ use std::os::unix::prelude::*;
+ 
+-use sys::termios::Termios;
+-use unistd::ForkResult;
+-use {Result, Error, fcntl};
+-use errno::Errno;
++use crate::sys::termios::Termios;
++use crate::unistd::{self, ForkResult, Pid};
++use crate::{Result, Error, fcntl};
++use crate::errno::Errno;
+ 
+ /// Representation of a master/slave pty pair
+ ///
+@@ -44,7 +43,7 @@ pub struct ForkptyResult {
+ /// 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 {
+@@ -70,13 +69,28 @@ impl Drop for PtyMaster {
+         // invalid file descriptor.  That frequently indicates a double-close
+         // condition, which can cause confusing errors for future I/O
+         // operations.
+-        let e = ::unistd::close(self.0);
++        let e = unistd::close(self.0);
+         if e == Err(Error::Sys(Errno::EBADF)) {
+             panic!("Closing an invalid file descriptor!");
+         };
+     }
+ }
+ 
++impl io::Read for PtyMaster {
++    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
++        unistd::read(self.0, buf).map_err(|e| e.as_errno().unwrap().into())
++    }
++}
++
++impl io::Write for PtyMaster {
++    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
++        unistd::write(self.0, buf).map_err(|e| e.as_errno().unwrap().into())
++    }
++    fn flush(&mut self) -> io::Result<()> {
++        Ok(())
++    }
++}
++
+ /// Grant access to a slave pseudoterminal (see
+ /// [`grantpt(3)`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/grantpt.html))
+ ///
+@@ -218,16 +232,16 @@ pub fn unlockpt(fd: &PtyMaster) -> Result<()> {
+ pub fn openpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>>>(winsize: T, termios: U) -> Result<OpenptyResult> {
+     use std::ptr;
+ 
+-    let mut slave: libc::c_int = unsafe { mem::uninitialized() };
+-    let mut master: libc::c_int = unsafe { mem::uninitialized() };
++    let mut slave = mem::MaybeUninit::<libc::c_int>::uninit();
++    let mut master = mem::MaybeUninit::<libc::c_int>::uninit();
+     let ret = {
+         match (termios.into(), winsize.into()) {
+             (Some(termios), Some(winsize)) => {
+                 let inner_termios = termios.get_libc_termios();
+                 unsafe {
+                     libc::openpty(
+-                        &mut master,
+-                        &mut slave,
++                        master.as_mut_ptr(),
++                        slave.as_mut_ptr(),
+                         ptr::null_mut(),
+                         &*inner_termios as *const libc::termios as *mut _,
+                         winsize as *const Winsize as *mut _,
+@@ -237,8 +251,8 @@ pub fn openpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>
+             (None, Some(winsize)) => {
+                 unsafe {
+                     libc::openpty(
+-                        &mut master,
+-                        &mut slave,
++                        master.as_mut_ptr(),
++                        slave.as_mut_ptr(),
+                         ptr::null_mut(),
+                         ptr::null_mut(),
+                         winsize as *const Winsize as *mut _,
+@@ -249,8 +263,8 @@ pub fn openpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>
+                 let inner_termios = termios.get_libc_termios();
+                 unsafe {
+                     libc::openpty(
+-                        &mut master,
+-                        &mut slave,
++                        master.as_mut_ptr(),
++                        slave.as_mut_ptr(),
+                         ptr::null_mut(),
+                         &*inner_termios as *const libc::termios as *mut _,
+                         ptr::null_mut(),
+@@ -260,8 +274,8 @@ pub fn openpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>
+             (None, None) => {
+                 unsafe {
+                     libc::openpty(
+-                        &mut master,
+-                        &mut slave,
++                        master.as_mut_ptr(),
++                        slave.as_mut_ptr(),
+                         ptr::null_mut(),
+                         ptr::null_mut(),
+                         ptr::null_mut(),
+@@ -273,10 +287,12 @@ pub fn openpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>
+ 
+     Errno::result(ret)?;
+ 
+-    Ok(OpenptyResult {
+-        master: master,
+-        slave: slave,
+-    })
++    unsafe {
++        Ok(OpenptyResult {
++            master: master.assume_init(),
++            slave: slave.assume_init(),
++        })
++    }
+ }
+ 
+ /// Create a new pseudoterminal, returning the master file descriptor and forked pid.
+@@ -291,10 +307,8 @@ pub fn forkpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>
+     termios: U,
+ ) -> Result<ForkptyResult> {
+     use std::ptr;
+-    use unistd::Pid;
+-    use unistd::ForkResult::*;
+ 
+-    let mut master: libc::c_int = unsafe { mem::uninitialized() };
++    let mut master = mem::MaybeUninit::<libc::c_int>::uninit();
+ 
+     let term = match termios.into() {
+         Some(termios) => {
+@@ -310,17 +324,19 @@ pub fn forkpty<'a, 'b, T: Into<Option<&'a Winsize>>, U: Into<Option<&'b Termios>
+         .unwrap_or(ptr::null_mut());
+ 
+     let res = unsafe {
+-        libc::forkpty(&mut master, ptr::null_mut(), term, win)
++        libc::forkpty(master.as_mut_ptr(), ptr::null_mut(), term, win)
+     };
+ 
+     let fork_result = Errno::result(res).map(|res| match res {
+-        0 => Child,
+-        res => Parent { child: Pid::from_raw(res) },
++        0 => ForkResult::Child,
++        res => ForkResult::Parent { child: Pid::from_raw(res) },
+     })?;
+ 
+-    Ok(ForkptyResult {
+-        master: master,
+-        fork_result: fork_result,
+-    })
++    unsafe {
++        Ok(ForkptyResult {
++            master: master.assume_init(),
++            fork_result,
++        })
++    }
+ }
+ 
+diff --git a/third_party/rust/nix/src/sched.rs b/third_party/rust/nix/src/sched.rs
+index 67188c57eef7d..3b48b4adf6d05 100644
+--- a/third_party/rust/nix/src/sched.rs
++++ b/third_party/rust/nix/src/sched.rs
+@@ -1,18 +1,17 @@
+-use libc;
+-use {Errno, Result};
++use crate::{Errno, Result};
+ 
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ pub use self::sched_linux_like::*;
+ 
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ mod sched_linux_like {
+-    use errno::Errno;
++    use crate::errno::Errno;
+     use libc::{self, c_int, c_void};
+     use std::mem;
+     use std::option::Option;
+     use std::os::unix::io::RawFd;
+-    use unistd::Pid;
+-    use {Error, Result};
++    use crate::unistd::Pid;
++    use crate::{Error, Result};
+ 
+     // For some functions taking with a parameter of type CloneFlags,
+     // only a subset of these flags have an effect.
+@@ -46,6 +45,11 @@ mod sched_linux_like {
+ 
+     pub type CloneCb<'a> = Box<dyn FnMut() -> isize + 'a>;
+ 
++    /// CpuSet represent a bit-mask of CPUs.
++    /// CpuSets are used by sched_setaffinity and
++    /// sched_getaffinity for example.
++    ///
++    /// This is a wrapper around `libc::cpu_set_t`.
+     #[repr(C)]
+     #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+     pub struct CpuSet {
+@@ -53,37 +57,78 @@ mod sched_linux_like {
+     }
+ 
+     impl CpuSet {
++        /// Create a new and empty CpuSet.
+         pub fn new() -> CpuSet {
+             CpuSet {
+                 cpu_set: unsafe { mem::zeroed() },
+             }
+         }
+ 
++        /// Test to see if a CPU is in the CpuSet.
++        /// `field` is the CPU id to test
+         pub fn is_set(&self, field: usize) -> Result<bool> {
+-            if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
++            if field >= CpuSet::count() {
+                 Err(Error::Sys(Errno::EINVAL))
+             } else {
+                 Ok(unsafe { libc::CPU_ISSET(field, &self.cpu_set) })
+             }
+         }
+ 
++        /// Add a CPU to CpuSet.
++        /// `field` is the CPU id to add
+         pub fn set(&mut self, field: usize) -> Result<()> {
+-            if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
++            if field >= CpuSet::count() {
+                 Err(Error::Sys(Errno::EINVAL))
+             } else {
+-                Ok(unsafe { libc::CPU_SET(field, &mut self.cpu_set) })
++                unsafe { libc::CPU_SET(field, &mut self.cpu_set); }
++                Ok(())
+             }
+         }
+ 
++        /// Remove a CPU from CpuSet.
++        /// `field` is the CPU id to remove
+         pub fn unset(&mut self, field: usize) -> Result<()> {
+-            if field >= 8 * mem::size_of::<libc::cpu_set_t>() {
++            if field >= CpuSet::count() {
+                 Err(Error::Sys(Errno::EINVAL))
+             } else {
+-                Ok(unsafe { libc::CPU_CLR(field, &mut self.cpu_set) })
++                unsafe { libc::CPU_CLR(field, &mut self.cpu_set);}
++                Ok(())
+             }
+         }
++
++        /// Return the maximum number of CPU in CpuSet
++        pub fn count() -> usize {
++            8 * mem::size_of::<libc::cpu_set_t>()
++        }
+     }
+ 
++    impl Default for CpuSet {
++        fn default() -> Self {
++            Self::new()
++        }
++    }
++
++    /// `sched_setaffinity` set a thread's CPU affinity mask
++    /// ([`sched_setaffinity(2)`](http://man7.org/linux/man-pages/man2/sched_setaffinity.2.html))
++    ///
++    /// `pid` is the thread ID to update.
++    /// If pid is zero, then the calling thread is updated.
++    ///
++    /// The `cpuset` argument specifies the set of CPUs on which the thread
++    /// will be eligible to run.
++    ///
++    /// # Example
++    ///
++    /// Binding the current thread to CPU 0 can be done as follows:
++    ///
++    /// ```rust,no_run
++    /// use nix::sched::{CpuSet, sched_setaffinity};
++    /// use nix::unistd::Pid;
++    ///
++    /// let mut cpu_set = CpuSet::new();
++    /// cpu_set.set(0);
++    /// sched_setaffinity(Pid::from_raw(0), &cpu_set);
++    /// ```
+     pub fn sched_setaffinity(pid: Pid, cpuset: &CpuSet) -> Result<()> {
+         let res = unsafe {
+             libc::sched_setaffinity(
+@@ -96,6 +141,41 @@ mod sched_linux_like {
+         Errno::result(res).map(drop)
+     }
+ 
++    /// `sched_getaffinity` get a thread's CPU affinity mask
++    /// ([`sched_getaffinity(2)`](http://man7.org/linux/man-pages/man2/sched_getaffinity.2.html))
++    ///
++    /// `pid` is the thread ID to check.
++    /// If pid is zero, then the calling thread is checked.
++    ///
++    /// Returned `cpuset` is the set of CPUs on which the thread
++    /// is eligible to run.
++    ///
++    /// # Example
++    ///
++    /// Checking if the current thread can run on CPU 0 can be done as follows:
++    ///
++    /// ```rust,no_run
++    /// use nix::sched::sched_getaffinity;
++    /// use nix::unistd::Pid;
++    ///
++    /// let cpu_set = sched_getaffinity(Pid::from_raw(0)).unwrap();
++    /// if cpu_set.is_set(0).unwrap() {
++    ///     println!("Current thread can run on CPU 0");
++    /// }
++    /// ```
++    pub fn sched_getaffinity(pid: Pid) -> Result<CpuSet> {
++        let mut cpuset = CpuSet::new();
++        let res = unsafe {
++            libc::sched_getaffinity(
++                pid.into(),
++                mem::size_of::<CpuSet>() as libc::size_t,
++                &mut cpuset.cpu_set,
++            )
++        };
++
++        Errno::result(res).and(Ok(cpuset))
++    }
++
+     pub fn clone(
+         mut cb: CloneCb,
+         stack: &mut [u8],
+@@ -109,8 +189,8 @@ mod sched_linux_like {
+ 
+         let res = unsafe {
+             let combined = flags.bits() | signal.unwrap_or(0);
+-            let ptr = stack.as_mut_ptr().offset(stack.len() as isize);
+-            let ptr_aligned = ptr.offset((ptr as usize % 16) as isize * -1);
++            let ptr = stack.as_mut_ptr().add(stack.len());
++            let ptr_aligned = ptr.sub(ptr as usize % 16);
+             libc::clone(
+                 mem::transmute(
+                     callback as extern "C" fn(*mut Box<dyn FnMut() -> isize>) -> i32,
+diff --git a/third_party/rust/nix/src/sys/aio.rs b/third_party/rust/nix/src/sys/aio.rs
+index 9258a0657cc8a..1afdb35866c28 100644
+--- a/third_party/rust/nix/src/sys/aio.rs
++++ b/third_party/rust/nix/src/sys/aio.rs
+@@ -21,20 +21,19 @@
+ //! [`aio_cancel_all`](fn.aio_cancel_all.html), though the operating system may
+ //! not support this for all filesystems and devices.
+ 
+-use {Error, Result};
+-use errno::Errno;
++use crate::{Error, Result};
++use crate::errno::Errno;
+ use std::os::unix::io::RawFd;
+ use libc::{c_void, off_t, size_t};
+-use libc;
+ use std::borrow::{Borrow, BorrowMut};
+ use std::fmt;
+ use std::fmt::Debug;
+ use std::marker::PhantomData;
+ use std::mem;
+ use std::ptr::{null, null_mut};
+-use sys::signal::*;
++use crate::sys::signal::*;
+ use std::thread;
+-use sys::time::TimeSpec;
++use crate::sys::time::TimeSpec;
+ 
+ libc_enum! {
+     /// Mode for `AioCb::fsync`.  Controls whether only data or both data and
+@@ -226,8 +225,6 @@ impl<'a> AioCb<'a> {
+     /// [`fsync`](#method.fsync) operation.
+     ///
+     /// ```
+-    /// # extern crate tempfile;
+-    /// # extern crate nix;
+     /// # use nix::errno::Errno;
+     /// # use nix::Error;
+     /// # use nix::sys::aio::*;
+@@ -287,8 +284,6 @@ impl<'a> AioCb<'a> {
+     /// Create an `AioCb` from a mutable slice and read into it.
+     ///
+     /// ```
+-    /// # extern crate tempfile;
+-    /// # extern crate nix;
+     /// # use nix::errno::Errno;
+     /// # use nix::Error;
+     /// # use nix::sys::aio::*;
+@@ -363,8 +358,6 @@ impl<'a> AioCb<'a> {
+     /// Create an `AioCb` from a Vector and use it for writing
+     ///
+     /// ```
+-    /// # extern crate tempfile;
+-    /// # extern crate nix;
+     /// # use nix::errno::Errno;
+     /// # use nix::Error;
+     /// # use nix::sys::aio::*;
+@@ -394,9 +387,6 @@ impl<'a> AioCb<'a> {
+     /// Create an `AioCb` from a `Bytes` object
+     ///
+     /// ```
+-    /// # extern crate bytes;
+-    /// # extern crate tempfile;
+-    /// # extern crate nix;
+     /// # use bytes::Bytes;
+     /// # use nix::sys::aio::*;
+     /// # use nix::sys::signal::SigevNotify;
+@@ -419,9 +409,6 @@ impl<'a> AioCb<'a> {
+     /// using an un`Box`ed `Bytes` object.
+     ///
+     /// ```
+-    /// # extern crate bytes;
+-    /// # extern crate tempfile;
+-    /// # extern crate nix;
+     /// # use bytes::Bytes;
+     /// # use nix::sys::aio::*;
+     /// # use nix::sys::signal::SigevNotify;
+@@ -480,8 +467,6 @@ impl<'a> AioCb<'a> {
+     /// Create an `AioCb` from a Vector and use it for reading
+     ///
+     /// ```
+-    /// # extern crate tempfile;
+-    /// # extern crate nix;
+     /// # use nix::errno::Errno;
+     /// # use nix::Error;
+     /// # use nix::sys::aio::*;
+@@ -642,8 +627,6 @@ impl<'a> AioCb<'a> {
+     /// Construct an `AioCb` from a slice and use it for writing.
+     ///
+     /// ```
+-    /// # extern crate tempfile;
+-    /// # extern crate nix;
+     /// # use nix::errno::Errno;
+     /// # use nix::Error;
+     /// # use nix::sys::aio::*;
+@@ -726,8 +709,6 @@ impl<'a> AioCb<'a> {
+     /// result.
+     ///
+     /// ```
+-    /// # extern crate tempfile;
+-    /// # extern crate nix;
+     /// # use nix::errno::Errno;
+     /// # use nix::Error;
+     /// # use nix::sys::aio::*;
+@@ -781,8 +762,6 @@ impl<'a> AioCb<'a> {
+     /// is an alternative to `aio_suspend`, used by most of the other examples.
+     ///
+     /// ```
+-    /// # extern crate tempfile;
+-    /// # extern crate nix;
+     /// # use nix::errno::Errno;
+     /// # use nix::Error;
+     /// # use nix::sys::aio::*;
+@@ -925,8 +904,6 @@ impl<'a> AioCb<'a> {
+ /// descriptor.
+ ///
+ /// ```
+-/// # extern crate tempfile;
+-/// # extern crate nix;
+ /// # use nix::errno::Errno;
+ /// # use nix::Error;
+ /// # use nix::sys::aio::*;
+@@ -978,13 +955,7 @@ pub fn aio_cancel_all(fd: RawFd) -> Result<AioCancelStat> {
+ ///
+ /// Use `aio_suspend` to block until an aio operation completes.
+ ///
+-// Disable doctest due to a known bug in FreeBSD's 32-bit emulation.  The fix
+-// will be included in release 11.2.
+-// FIXME reenable the doc test when the CI machine gets upgraded to that release.
+-// https://svnweb.freebsd.org/base?view=revision&revision=325018
+-/// ```no_run
+-/// # extern crate tempfile;
+-/// # extern crate nix;
++/// ```
+ /// # use nix::sys::aio::*;
+ /// # use nix::sys::signal::SigevNotify;
+ /// # use std::os::unix::io::AsRawFd;
+@@ -1091,8 +1062,6 @@ impl<'a> LioCb<'a> {
+     /// [`AioCb::error`] to poll.
+     ///
+     /// ```
+-    /// # extern crate tempfile;
+-    /// # extern crate nix;
+     /// # use nix::sys::aio::*;
+     /// # use nix::sys::signal::SigevNotify;
+     /// # use std::os::unix::io::AsRawFd;
+@@ -1148,8 +1117,6 @@ impl<'a> LioCb<'a> {
+     ///
+     /// # Examples
+     /// ```no_run
+-    /// # extern crate tempfile;
+-    /// # extern crate nix;
+     /// # use nix::Error;
+     /// # use nix::errno::Errno;
+     /// # use nix::sys::aio::*;
+@@ -1213,7 +1180,6 @@ impl<'a> LioCb<'a> {
+                 },
+                 Err(Error::Sys(Errno::EINPROGRESS)) => {
+                     // aiocb is was successfully queued; no need to do anything
+-                    ()
+                 },
+                 Err(Error::Sys(Errno::EINVAL)) => panic!(
+                     "AioCb was never submitted, or already finalized"),
+diff --git a/third_party/rust/nix/src/sys/epoll.rs b/third_party/rust/nix/src/sys/epoll.rs
+index fef6f4e3ec92c..2437bbe2ddb3b 100644
+--- a/third_party/rust/nix/src/sys/epoll.rs
++++ b/third_party/rust/nix/src/sys/epoll.rs
+@@ -1,10 +1,10 @@
+-use Result;
+-use errno::Errno;
++use crate::Result;
++use crate::errno::Errno;
+ use libc::{self, c_int};
+ use std::os::unix::io::RawFd;
+ use std::ptr;
+ use std::mem;
+-use ::Error;
++use crate::Error;
+ 
+ libc_bitflags!(
+     pub struct EpollFlags: c_int {
+@@ -43,7 +43,7 @@ libc_bitflags!{
+ }
+ 
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+-#[repr(C)]
++#[repr(transparent)]
+ pub struct EpollEvent {
+     event: libc::epoll_event,
+ }
+diff --git a/third_party/rust/nix/src/sys/event.rs b/third_party/rust/nix/src/sys/event.rs
+index 8cd7372f88188..8050af313245d 100644
+--- a/third_party/rust/nix/src/sys/event.rs
++++ b/third_party/rust/nix/src/sys/event.rs
+@@ -1,12 +1,11 @@
+ /* TOOD: Implement for other kqueue based systems
+  */
+ 
+-use {Errno, Result};
++use crate::{Errno, Result};
+ #[cfg(not(target_os = "netbsd"))]
+ use libc::{timespec, time_t, c_int, c_long, intptr_t, uintptr_t};
+ #[cfg(target_os = "netbsd")]
+ use libc::{timespec, time_t, c_long, intptr_t, uintptr_t, size_t};
+-use libc;
+ use std::os::unix::io::RawFd;
+ use std::ptr;
+ use std::mem;
+@@ -28,7 +27,7 @@ type type_of_data = intptr_t;
+ #[cfg(any(target_os = "netbsd"))]
+ type type_of_udata = intptr_t;
+ #[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
+-type type_of_data = libc::int64_t;
++type type_of_data = i64;
+ 
+ #[cfg(target_os = "netbsd")]
+ type type_of_event_filter = u32;
+@@ -90,14 +89,9 @@ libc_bitflags!{
+         EV_CLEAR;
+         EV_DELETE;
+         EV_DISABLE;
+-        // No released version of OpenBSD supports EV_DISPATCH or EV_RECEIPT.
+-        // These have been commited to the -current branch though and are
+-        // expected to be part of the OpenBSD 6.2 release in Nov 2017.
+-        // See: https://marc.info/?l=openbsd-tech&m=149621427511219&w=2
+-        // https://github.com/rust-lang/libc/pull/613
+         #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
+                   target_os = "ios", target_os = "macos",
+-                  target_os = "netbsd"))]
++                  target_os = "netbsd", target_os = "openbsd"))]
+         EV_DISPATCH;
+         #[cfg(target_os = "freebsd")]
+         EV_DROP;
+@@ -116,7 +110,7 @@ libc_bitflags!{
+         EV_POLL;
+         #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
+                   target_os = "ios", target_os = "macos",
+-                  target_os = "netbsd"))]
++                  target_os = "netbsd", target_os = "openbsd"))]
+         EV_RECEIPT;
+         EV_SYSFLAGS;
+     }
+@@ -134,10 +128,6 @@ libc_bitflags!(
+         NOTE_EXEC;
+         NOTE_EXIT;
+         #[cfg(any(target_os = "macos", target_os = "ios"))]
+-        #[deprecated( since="0.14.0", note="Deprecated since OSX 10.9")]
+-        #[allow(deprecated)]
+-        NOTE_EXIT_REPARENTED;
+-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+         NOTE_EXITSTATUS;
+         NOTE_EXTEND;
+         #[cfg(any(target_os = "macos",
+@@ -183,11 +173,6 @@ libc_bitflags!(
+         NOTE_OOB;
+         NOTE_PCTRLMASK;
+         NOTE_PDATAMASK;
+-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+-        #[cfg(any(target_os = "macos", target_os = "ios"))]
+-        #[deprecated( since="0.14.0", note="Deprecated since OSX 10.9")]
+-        #[allow(deprecated)]
+-        NOTE_REAP;
+         NOTE_RENAME;
+         NOTE_REVOKE;
+         #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd"))]
+@@ -234,7 +219,7 @@ impl KEvent {
+     pub fn new(ident: uintptr_t, filter: EventFilter, flags: EventFlag,
+                fflags:FilterFlag, data: intptr_t, udata: intptr_t) -> KEvent {
+         KEvent { kevent: libc::kevent {
+-            ident: ident,
++            ident,
+             filter: filter as type_of_event_filter,
+             flags: flags.bits(),
+             fflags: fflags.bits(),
+@@ -329,23 +314,17 @@ pub fn ev_set(ev: &mut KEvent,
+ fn test_struct_kevent() {
+     let udata : intptr_t = 12345;
+ 
+-    let expected = libc::kevent{ident: 0xdead_beef,
+-                                filter: libc::EVFILT_READ,
+-                                flags: libc::EV_ONESHOT | libc::EV_ADD,
+-                                fflags: libc::NOTE_CHILD | libc::NOTE_EXIT,
+-                                data: 0x1337,
+-                                udata: udata as type_of_udata};
+     let actual = KEvent::new(0xdead_beef,
+                              EventFilter::EVFILT_READ,
+                              EventFlag::EV_ONESHOT | EventFlag::EV_ADD,
+                              FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT,
+                              0x1337,
+                              udata);
+-    assert!(expected.ident == actual.ident());
+-    assert!(expected.filter == actual.filter() as type_of_event_filter);
+-    assert!(expected.flags == actual.flags().bits());
+-    assert!(expected.fflags == actual.fflags().bits());
+-    assert!(expected.data == actual.data() as type_of_data);
+-    assert!(expected.udata == actual.udata() as type_of_udata);
+-    assert!(mem::size_of::<libc::kevent>() == mem::size_of::<KEvent>());
++    assert_eq!(0xdead_beef, actual.ident());
++    assert_eq!(libc::EVFILT_READ, actual.filter() as type_of_event_filter);
++    assert_eq!(libc::EV_ONESHOT | libc::EV_ADD, actual.flags().bits());
++    assert_eq!(libc::NOTE_CHILD | libc::NOTE_EXIT, actual.fflags().bits());
++    assert_eq!(0x1337, actual.data() as type_of_data);
++    assert_eq!(udata as type_of_udata, actual.udata() as type_of_udata);
++    assert_eq!(mem::size_of::<libc::kevent>(), mem::size_of::<KEvent>());
+ }
+diff --git a/third_party/rust/nix/src/sys/eventfd.rs b/third_party/rust/nix/src/sys/eventfd.rs
+index c5a54e46a1735..baaaa89ddd52e 100644
+--- a/third_party/rust/nix/src/sys/eventfd.rs
++++ b/third_party/rust/nix/src/sys/eventfd.rs
+@@ -1,7 +1,7 @@
+ use libc;
+ use std::os::unix::io::RawFd;
+-use Result;
+-use errno::Errno;
++use crate::Result;
++use crate::errno::Errno;
+ 
+ libc_bitflags! {
+     pub struct EfdFlags: libc::c_int {
+diff --git a/third_party/rust/nix/src/sys/inotify.rs b/third_party/rust/nix/src/sys/inotify.rs
+index e6c2cf64d29dc..4880a4a514e77 100644
+--- a/third_party/rust/nix/src/sys/inotify.rs
++++ b/third_party/rust/nix/src/sys/inotify.rs
+@@ -23,19 +23,19 @@
+ //! }
+ //! ```
+ 
+-use libc;
+ use libc::{
+     c_char,
+     c_int,
+ };
+ use std::ffi::{OsString,OsStr,CStr};
+ use std::os::unix::ffi::OsStrExt;
+-use std::mem::size_of;
++use std::mem::{MaybeUninit, size_of};
+ use std::os::unix::io::{RawFd,AsRawFd,FromRawFd};
+-use unistd::read;
+-use Result;
+-use NixPath;
+-use errno::Errno;
++use std::ptr;
++use crate::unistd::read;
++use crate::Result;
++use crate::NixPath;
++use crate::errno::Errno;
+ 
+ libc_bitflags! {
+     /// Configuration options for [`inotify_add_watch`](fn.inotify_add_watch.html).
+@@ -131,7 +131,7 @@ impl Inotify {
+     /// Returns a watch descriptor. This is not a File Descriptor! 
+     ///
+     /// For more information see, [inotify_add_watch(2)](http://man7.org/linux/man-pages/man2/inotify_add_watch.2.html).
+-    pub fn add_watch<P: ?Sized + NixPath>(&self,
++    pub fn add_watch<P: ?Sized + NixPath>(self,
+                                           path: &P,
+                                           mask: AddWatchFlags) 
+                                             -> Result<WatchDescriptor>
+@@ -152,14 +152,14 @@ impl Inotify {
+     ///
+     /// For more information see, [inotify_rm_watch(2)](http://man7.org/linux/man-pages/man2/inotify_rm_watch.2.html).
+     #[cfg(target_os = "linux")]
+-    pub fn rm_watch(&self, wd: WatchDescriptor) -> Result<()> {
++    pub fn rm_watch(self, wd: WatchDescriptor) -> Result<()> {
+         let res = unsafe { libc::inotify_rm_watch(self.fd, wd.wd) };
+ 
+         Errno::result(res).map(drop)
+     }
+ 
+     #[cfg(target_os = "android")]
+-    pub fn rm_watch(&self, wd: WatchDescriptor) -> Result<()> {
++    pub fn rm_watch(self, wd: WatchDescriptor) -> Result<()> {
+         let res = unsafe { libc::inotify_rm_watch(self.fd, wd.wd as u32) };
+ 
+         Errno::result(res).map(drop)
+@@ -171,9 +171,10 @@ impl Inotify {
+     /// 
+     /// Returns as many events as available. If the call was non blocking and no
+     /// events could be read then the EAGAIN error is returned.
+-    pub fn read_events(&self) -> Result<Vec<InotifyEvent>> {
++    pub fn read_events(self) -> Result<Vec<InotifyEvent>> {
+         let header_size = size_of::<libc::inotify_event>();
+-        let mut buffer = [0u8; 4096];
++        const BUFSIZ: usize = 4096;
++        let mut buffer = [0u8; BUFSIZ];
+         let mut events = Vec::new();
+         let mut offset = 0;
+ 
+@@ -181,11 +182,13 @@ impl Inotify {
+ 
+         while (nread - offset) >= header_size {
+             let event = unsafe {
+-                &*(
+-                    buffer
+-                        .as_ptr()
+-                        .offset(offset as isize) as *const libc::inotify_event
+-                )
++                let mut event = MaybeUninit::<libc::inotify_event>::uninit();
++                ptr::copy_nonoverlapping(
++                    buffer.as_ptr().add(offset),
++                    event.as_mut_ptr() as *mut u8,
++                    (BUFSIZ - offset).min(header_size)
++                );
++                event.assume_init()
+             };
+ 
+             let name = match event.len {
+@@ -194,7 +197,7 @@ impl Inotify {
+                     let ptr = unsafe { 
+                         buffer
+                             .as_ptr()
+-                            .offset(offset as isize + header_size as isize)
++                            .add(offset + header_size)
+                             as *const c_char
+                     };
+                     let cstr = unsafe { CStr::from_ptr(ptr) };
+diff --git a/third_party/rust/nix/src/sys/ioctl/bsd.rs b/third_party/rust/nix/src/sys/ioctl/bsd.rs
+index 9b8b0ff1a155f..f39c0eb688f8a 100644
+--- a/third_party/rust/nix/src/sys/ioctl/bsd.rs
++++ b/third_party/rust/nix/src/sys/ioctl/bsd.rs
+@@ -6,7 +6,7 @@ pub type ioctl_num_type = ::libc::c_ulong;
+ pub type ioctl_param_type = ::libc::c_int;
+ 
+ mod consts {
+-    use ::sys::ioctl::ioctl_num_type;
++    use crate::sys::ioctl::ioctl_num_type;
+     #[doc(hidden)]
+     pub const VOID: ioctl_num_type = 0x2000_0000;
+     #[doc(hidden)]
+@@ -14,7 +14,7 @@ mod consts {
+     #[doc(hidden)]
+     pub const IN: ioctl_num_type = 0x8000_0000;
+     #[doc(hidden)]
+-    pub const INOUT: ioctl_num_type = (IN|OUT);
++    pub const INOUT: ioctl_num_type = IN|OUT;
+     #[doc(hidden)]
+     pub const IOCPARM_MASK: ioctl_num_type = 0x1fff;
+ }
+diff --git a/third_party/rust/nix/src/sys/ioctl/linux.rs b/third_party/rust/nix/src/sys/ioctl/linux.rs
+index 9cdac72a4b80b..68ebaba9bf496 100644
+--- a/third_party/rust/nix/src/sys/ioctl/linux.rs
++++ b/third_party/rust/nix/src/sys/ioctl/linux.rs
+@@ -33,7 +33,8 @@ mod consts {
+           target_arch = "arm",
+           target_arch = "s390x",
+           target_arch = "x86_64",
+-          target_arch = "aarch64"))]
++          target_arch = "aarch64",
++          target_arch = "riscv64"))]
+ mod consts {
+     #[doc(hidden)]
+     pub const NONE: u8 = 0;
+diff --git a/third_party/rust/nix/src/sys/ioctl/mod.rs b/third_party/rust/nix/src/sys/ioctl/mod.rs
+index 4513bf877434a..8858a9d57779f 100644
+--- a/third_party/rust/nix/src/sys/ioctl/mod.rs
++++ b/third_party/rust/nix/src/sys/ioctl/mod.rs
+@@ -29,7 +29,7 @@
+ //! Historically `ioctl` numbers were arbitrary hard-coded values. In Linux (before 2.6) and some
+ //! unices this has changed to a more-ordered system where the ioctl numbers are partitioned into
+ //! subcomponents (For linux this is documented in
+-//! [`Documentation/ioctl/ioctl-number.txt`](http://elixir.free-electrons.com/linux/latest/source/Documentation/ioctl/ioctl-number.txt)):
++//! [`Documentation/ioctl/ioctl-number.rst`](https://elixir.bootlin.com/linux/latest/source/Documentation/userspace-api/ioctl/ioctl-number.rst)):
+ //!
+ //!   * Number: The actual ioctl ID
+ //!   * Type: A grouping of ioctls for a common purpose or driver
+@@ -221,11 +221,13 @@
+ //!
+ //! # fn main() {}
+ //! ```
+-#[cfg(any(target_os = "android", target_os = "linux"))]
++use cfg_if::cfg_if;
++
++#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
+ #[macro_use]
+ mod linux;
+ 
+-#[cfg(any(target_os = "android", target_os = "linux"))]
++#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
+ pub use self::linux::*;
+ 
+ #[cfg(any(target_os = "dragonfly",
+@@ -317,7 +319,6 @@ macro_rules! ioctl_none {
+ ///
+ /// ```no_run
+ /// # #[macro_use] extern crate nix;
+-/// # extern crate libc;
+ /// # use libc::TIOCNXCL;
+ /// # use std::fs::File;
+ /// # use std::os::unix::io::AsRawFd;
+@@ -396,7 +397,6 @@ macro_rules! ioctl_read {
+ /// # Example
+ ///
+ /// ```
+-/// # extern crate libc;
+ /// # #[macro_use] extern crate nix;
+ /// # #[cfg(any(target_os = "android", target_os = "linux"))]
+ /// ioctl_read_bad!(tcgets, libc::TCGETS, libc::termios);
+@@ -470,7 +470,6 @@ macro_rules! ioctl_write_ptr {
+ /// # Example
+ ///
+ /// ```
+-/// # extern crate libc;
+ /// # #[macro_use] extern crate nix;
+ /// # #[cfg(any(target_os = "android", target_os = "linux"))]
+ /// ioctl_write_ptr_bad!(tcsets, libc::TCSETS, libc::termios);
+@@ -590,7 +589,6 @@ cfg_if!{
+ /// # Examples
+ ///
+ /// ```
+-/// # extern crate libc;
+ /// # #[macro_use] extern crate nix;
+ /// # #[cfg(any(target_os = "android", target_os = "linux"))]
+ /// ioctl_write_int_bad!(tcsbrk, libc::TCSBRK);
+diff --git a/third_party/rust/nix/src/sys/memfd.rs b/third_party/rust/nix/src/sys/memfd.rs
+index 9672429b31e7f..51b7e6b18849b 100644
+--- a/third_party/rust/nix/src/sys/memfd.rs
++++ b/third_party/rust/nix/src/sys/memfd.rs
+@@ -1,7 +1,7 @@
+ use libc;
+ use std::os::unix::io::RawFd;
+-use Result;
+-use errno::Errno;
++use crate::Result;
++use crate::errno::Errno;
+ use std::ffi::CStr;
+ 
+ libc_bitflags!(
+diff --git a/third_party/rust/nix/src/sys/mman.rs b/third_party/rust/nix/src/sys/mman.rs
+index 4e250501dd0f0..63a0779c19382 100644
+--- a/third_party/rust/nix/src/sys/mman.rs
++++ b/third_party/rust/nix/src/sys/mman.rs
+@@ -1,12 +1,12 @@
+-use {Error, Result};
++use crate::{Error, Result};
+ #[cfg(not(target_os = "android"))]
+-use NixPath;
+-use errno::Errno;
++use crate::NixPath;
++use crate::errno::Errno;
+ #[cfg(not(target_os = "android"))]
+-use fcntl::OFlag;
++use crate::fcntl::OFlag;
+ use libc::{self, c_int, c_void, size_t, off_t};
+ #[cfg(not(target_os = "android"))]
+-use sys::stat::Mode;
++use crate::sys::stat::Mode;
+ use std::os::unix::io::RawFd;
+ 
+ libc_bitflags!{
+@@ -77,6 +77,43 @@ libc_bitflags!{
+         /// Allocate the mapping using "huge pages."
+         #[cfg(any(target_os = "android", target_os = "linux"))]
+         MAP_HUGETLB;
++        /// Make use of 64KB huge page (must be supported by the system)
++        #[cfg(target_os = "linux")]
++        MAP_HUGE_64KB;
++        /// Make use of 512KB huge page (must be supported by the system)
++        #[cfg(target_os = "linux")]
++        MAP_HUGE_512KB;
++        /// Make use of 1MB huge page (must be supported by the system)
++        #[cfg(target_os = "linux")]
++        MAP_HUGE_1MB;
++        /// Make use of 2MB huge page (must be supported by the system)
++        #[cfg(target_os = "linux")]
++        MAP_HUGE_2MB;
++        /// Make use of 8MB huge page (must be supported by the system)
++        #[cfg(target_os = "linux")]
++        MAP_HUGE_8MB;
++        /// Make use of 16MB huge page (must be supported by the system)
++        #[cfg(target_os = "linux")]
++        MAP_HUGE_16MB;
++        /// Make use of 32MB huge page (must be supported by the system)
++        #[cfg(target_os = "linux")]
++        MAP_HUGE_32MB;
++        /// Make use of 256MB huge page (must be supported by the system)
++        #[cfg(target_os = "linux")]
++        MAP_HUGE_256MB;
++        /// Make use of 512MB huge page (must be supported by the system)
++        #[cfg(target_os = "linux")]
++        MAP_HUGE_512MB;
++        /// Make use of 1GB huge page (must be supported by the system)
++        #[cfg(target_os = "linux")]
++        MAP_HUGE_1GB;
++        /// Make use of 2GB huge page (must be supported by the system)
++        #[cfg(target_os = "linux")]
++        MAP_HUGE_2GB;
++        /// Make use of 16GB huge page (must be supported by the system)
++        #[cfg(target_os = "linux")]
++        MAP_HUGE_16GB;
++
+         /// Lock the mapped region into memory as with `mlock(2)`.
+         #[cfg(target_os = "netbsd")]
+         MAP_WIRED;
+@@ -102,6 +139,17 @@ libc_bitflags!{
+     }
+ }
+ 
++#[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.
+     ///
+@@ -223,20 +271,37 @@ libc_bitflags!{
+     }
+ }
+ 
+-/// Locks all memory pages that contain part of the address range with `length` bytes starting at
+-/// `addr`. Locked pages never move to the swap area.
++/// Locks all memory pages that contain part of the address range with `length`
++/// bytes starting at `addr`.
++///
++/// Locked pages never move to the swap area.
++///
++/// # Safety
++///
++/// `addr` must meet all the requirements described in the `mlock(2)` man page.
+ pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> {
+     Errno::result(libc::mlock(addr, length)).map(drop)
+ }
+ 
+-/// Unlocks all memory pages that contain part of the address range with `length` bytes starting at
+-/// `addr`.
++/// Unlocks all memory pages that contain part of the address range with
++/// `length` bytes starting at `addr`.
++///
++/// # Safety
++///
++/// `addr` must meet all the requirements described in the `munlock(2)` man
++/// page.
+ pub unsafe fn munlock(addr: *const c_void, length: size_t) -> Result<()> {
+     Errno::result(libc::munlock(addr, length)).map(drop)
+ }
+ 
+-/// Locks all memory pages mapped into this process' address space. Locked pages never move to the
+-/// swap area.
++/// Locks all memory pages mapped into this process' address space.
++///
++/// Locked pages never move to the swap area.
++///
++/// # Safety
++///
++/// `addr` must meet all the requirements described in the `mlockall(2)` man
++/// page.
+ pub fn mlockall(flags: MlockAllFlags) -> Result<()> {
+     unsafe { Errno::result(libc::mlockall(flags.bits())) }.map(drop)
+ }
+@@ -246,8 +311,11 @@ pub fn munlockall() -> Result<()> {
+     unsafe { Errno::result(libc::munlockall()) }.map(drop)
+ }
+ 
+-/// Calls to mmap are inherently unsafe, so they must be made in an unsafe block. Typically
+-/// a higher-level abstraction will hide the unsafe interactions with the mmap'd region.
++/// allocate memory, or map files or devices into memory
++///
++/// # Safety
++///
++/// See the `mmap(2)` man page for detailed requirements.
+ pub unsafe fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: MapFlags, fd: RawFd, offset: off_t) -> Result<*mut c_void> {
+     let ret = libc::mmap(addr, length, prot.bits(), flags.bits(), fd, offset);
+ 
+@@ -258,10 +326,46 @@ pub unsafe fn mmap(addr: *mut c_void, length: size_t, prot: ProtFlags, flags: Ma
+     }
+ }
+ 
++/// 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
++///
++/// `addr` must meet all the requirements described in the `munmap(2)` man
++/// page.
+ pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> {
+     Errno::result(libc::munmap(addr, len)).map(drop)
+ }
+ 
++/// give advice about use of memory
++///
++/// # Safety
++///
++/// See the `madvise(2)` man page.  Take special care when using
++/// `MmapAdvise::MADV_FREE`.
+ pub unsafe fn madvise(addr: *mut c_void, length: size_t, advise: MmapAdvise) -> Result<()> {
+     Errno::result(libc::madvise(addr, length, advise as i32)).map(drop)
+ }
+@@ -295,6 +399,12 @@ pub unsafe fn mprotect(addr: *mut c_void, length: size_t, prot: ProtFlags) -> Re
+     Errno::result(libc::mprotect(addr, length, prot.bits())).map(drop)
+ }
+ 
++/// synchronize a mapped region
++///
++/// # Safety
++///
++/// `addr` must meet all the requirements described in the `msync(2)` man
++/// page.
+ pub unsafe fn msync(addr: *mut c_void, length: size_t, flags: MsFlags) -> Result<()> {
+     Errno::result(libc::msync(addr, length, flags.bits())).map(drop)
+ }
+diff --git a/third_party/rust/nix/src/sys/mod.rs b/third_party/rust/nix/src/sys/mod.rs
+index d3c2f92bbaaea..438fb4fdcb438 100644
+--- a/third_party/rust/nix/src/sys/mod.rs
++++ b/third_party/rust/nix/src/sys/mod.rs
+@@ -25,6 +25,7 @@ pub mod eventfd;
+           target_os = "freebsd",
+           target_os = "ios",
+           target_os = "linux",
++          target_os = "redox",
+           target_os = "macos",
+           target_os = "netbsd",
+           target_os = "openbsd"))]
+@@ -34,8 +35,12 @@ pub mod ioctl;
+ #[cfg(target_os = "linux")]
+ pub mod memfd;
+ 
++#[cfg(not(target_os = "redox"))]
+ pub mod mman;
+ 
++#[cfg(target_os = "linux")]
++pub mod personality;
++
+ pub mod pthread;
+ 
+ #[cfg(any(target_os = "android",
+@@ -53,6 +58,7 @@ pub mod quota;
+ #[cfg(any(target_os = "linux"))]
+ pub mod reboot;
+ 
++#[cfg(not(target_os = "redox"))]
+ pub mod select;
+ 
+ #[cfg(any(target_os = "android",
+@@ -67,6 +73,7 @@ pub mod signal;
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ pub mod signalfd;
+ 
++#[cfg(not(target_os = "redox"))]
+ pub mod socket;
+ 
+ pub mod stat;
+@@ -98,3 +105,6 @@ pub mod wait;
+ 
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ pub mod inotify;
++
++#[cfg(target_os = "linux")]
++pub mod timerfd;
+diff --git a/third_party/rust/nix/src/sys/personality.rs b/third_party/rust/nix/src/sys/personality.rs
+new file mode 100644
+index 0000000000000..6548b654aa1f4
+--- /dev/null
++++ b/third_party/rust/nix/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/third_party/rust/nix/src/sys/ptrace/bsd.rs b/third_party/rust/nix/src/sys/ptrace/bsd.rs
+index 7797d10647ef4..e85afc761198b 100644
+--- a/third_party/rust/nix/src/sys/ptrace/bsd.rs
++++ b/third_party/rust/nix/src/sys/ptrace/bsd.rs
+@@ -1,9 +1,10 @@
+-use errno::Errno;
++use cfg_if::cfg_if;
++use crate::errno::Errno;
+ use libc::{self, c_int};
+ use std::ptr;
+-use sys::signal::Signal;
+-use unistd::Pid;
+-use Result;
++use crate::sys::signal::Signal;
++use crate::unistd::Pid;
++use crate::Result;
+ 
+ pub type RequestType = c_int;
+ 
+@@ -77,16 +78,23 @@ pub fn traceme() -> Result<()> {
+ 
+ /// Attach to a running process, as with `ptrace(PT_ATTACH, ...)`
+ ///
+-/// Attaches to the process specified in pid, making it a tracee of the calling process.
++/// Attaches to the process specified by `pid`, making it a tracee of the calling process.
+ pub fn attach(pid: Pid) -> Result<()> {
+     unsafe { ptrace_other(Request::PT_ATTACH, pid, ptr::null_mut(), 0).map(drop) }
+ }
+ 
+ /// Detaches the current running process, as with `ptrace(PT_DETACH, ...)`
+ ///
+-/// Detaches from the process specified in pid allowing it to run freely
+-pub fn detach(pid: Pid) -> Result<()> {
+-    unsafe { ptrace_other(Request::PT_DETACH, pid, ptr::null_mut(), 0).map(drop) }
++/// Detaches from the process specified by `pid` allowing it to run freely, optionally delivering a
++/// signal specified by `sig`.
++pub fn detach<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
++    let data = match sig.into() {
++        Some(s) => s as c_int,
++        None => 0,
++    };
++    unsafe {
++        ptrace_other(Request::PT_DETACH, pid, ptr::null_mut(), data).map(drop)
++    }
+ }
+ 
+ /// Restart the stopped tracee process, as with `ptrace(PTRACE_CONT, ...)`
+@@ -121,7 +129,6 @@ pub fn kill(pid: Pid) -> Result<()> {
+ ///
+ /// # Example
+ /// ```rust
+-/// extern crate nix;
+ /// use nix::sys::ptrace::step;
+ /// use nix::unistd::Pid;
+ /// use nix::sys::signal::Signal;
+diff --git a/third_party/rust/nix/src/sys/ptrace/linux.rs b/third_party/rust/nix/src/sys/ptrace/linux.rs
+index df15e66527562..8d1dd16e5dd76 100644
+--- a/third_party/rust/nix/src/sys/ptrace/linux.rs
++++ b/third_party/rust/nix/src/sys/ptrace/linux.rs
+@@ -1,18 +1,21 @@
+ //! For detailed description of the ptrace requests, consult `man ptrace`.
+ 
++use cfg_if::cfg_if;
+ use std::{mem, ptr};
+-use {Error, Result};
+-use errno::Errno;
++use crate::{Error, Result};
++use crate::errno::Errno;
+ use libc::{self, c_void, c_long, siginfo_t};
+-use ::unistd::Pid;
+-use sys::signal::Signal;
++use crate::unistd::Pid;
++use crate::sys::signal::Signal;
+ 
+ pub type AddressType = *mut ::libc::c_void;
+ 
+-#[cfg(all(target_os = "linux",
+-          any(target_arch = "x86_64",
+-              target_arch = "x86"),
+-          target_env = "gnu"))]
++#[cfg(all(
++    target_os = "linux",
++    any(all(target_arch = "x86_64",
++            any(target_env = "gnu", target_env = "musl")),
++        all(target_arch = "x86", target_env = "gnu"))
++))]
+ use libc::user_regs_struct;
+ 
+ cfg_if! {
+@@ -106,6 +109,12 @@ libc_enum!{
+         #[cfg(all(target_os = "linux", not(any(target_arch = "mips",
+                                                target_arch = "mips64"))))]
+         PTRACE_PEEKSIGINFO,
++        #[cfg(all(target_os = "linux", target_env = "gnu",
++                  any(target_arch = "x86", target_arch = "x86_64")))]
++        PTRACE_SYSEMU,
++        #[cfg(all(target_os = "linux", target_env = "gnu",
++                  any(target_arch = "x86", target_arch = "x86_64")))]
++        PTRACE_SYSEMU_SINGLESTEP,
+     }
+ }
+ 
+@@ -165,22 +174,6 @@ libc_bitflags! {
+     }
+ }
+ 
+-/// Performs a ptrace request. If the request in question is provided by a specialised function
+-/// this function will return an unsupported operation error.
+-#[deprecated(
+-    since="0.10.0",
+-    note="usages of `ptrace()` should be replaced with the specialized helper functions instead"
+-)]
+-pub unsafe fn ptrace(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
+-    use self::Request::*;
+-    match request {
+-        PTRACE_PEEKTEXT | PTRACE_PEEKDATA | PTRACE_GETSIGINFO | 
+-            PTRACE_GETEVENTMSG | PTRACE_SETSIGINFO | PTRACE_SETOPTIONS | 
+-            PTRACE_POKETEXT | PTRACE_POKEDATA | PTRACE_KILL => Err(Error::UnsupportedOperation),
+-        _ => ptrace_other(request, pid, addr, data)
+-    }
+-}
+-
+ fn ptrace_peek(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
+     let ret = unsafe {
+         Errno::clear();
+@@ -193,19 +186,23 @@ fn ptrace_peek(request: Request, pid: Pid, addr: AddressType, data: *mut c_void)
+ }
+ 
+ /// Get user registers, as with `ptrace(PTRACE_GETREGS, ...)`
+-#[cfg(all(target_os = "linux",
+-          any(target_arch = "x86_64",
+-              target_arch = "x86"),
+-          target_env = "gnu"))]
++#[cfg(all(
++    target_os = "linux",
++    any(all(target_arch = "x86_64",
++            any(target_env = "gnu", target_env = "musl")),
++        all(target_arch = "x86", target_env = "gnu"))
++))]
+ pub fn getregs(pid: Pid) -> Result<user_regs_struct> {
+     ptrace_get_data::<user_regs_struct>(Request::PTRACE_GETREGS, pid)
+ }
+ 
+ /// Set user registers, as with `ptrace(PTRACE_SETREGS, ...)`
+-#[cfg(all(target_os = "linux",
+-          any(target_arch = "x86_64",
+-              target_arch = "x86"),
+-          target_env = "gnu"))]
++#[cfg(all(
++    target_os = "linux",
++    any(all(target_arch = "x86_64",
++            any(target_env = "gnu", target_env = "musl")),
++        all(target_arch = "x86", target_env = "gnu"))
++))]
+ pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
+     let res = unsafe {
+         libc::ptrace(Request::PTRACE_SETREGS as RequestType,
+@@ -221,16 +218,15 @@ pub fn setregs(pid: Pid, regs: user_regs_struct) -> Result<()> {
+ /// and therefore use the data field to return values. This function handles these
+ /// requests.
+ fn ptrace_get_data<T>(request: Request, pid: Pid) -> Result<T> {
+-    // Creates an uninitialized pointer to store result in
+-    let data: T = unsafe { mem::uninitialized() };
++    let mut data = mem::MaybeUninit::uninit();
+     let res = unsafe {
+         libc::ptrace(request as RequestType,
+                      libc::pid_t::from(pid),
+                      ptr::null_mut::<T>(),
+-                     &data as *const _ as *const c_void)
++                     data.as_mut_ptr() as *const _ as *const c_void)
+     };
+     Errno::result(res)?;
+-    Ok(data)
++    Ok(unsafe{ data.assume_init() })
+ }
+ 
+ unsafe fn ptrace_other(request: Request, pid: Pid, addr: AddressType, data: *mut c_void) -> Result<c_long> {
+@@ -288,23 +284,45 @@ pub fn traceme() -> Result<()> {
+     }
+ }
+ 
+-/// Ask for next syscall, as with `ptrace(PTRACE_SYSCALL, ...)`
++/// Continue execution until the next syscall, as with `ptrace(PTRACE_SYSCALL, ...)`
+ ///
+-/// Arranges for the tracee to be stopped at the next entry to or exit from a system call.
+-pub fn syscall(pid: Pid) -> Result<()> {
++/// Arranges for the tracee to be stopped at the next entry to or exit from a system call,
++/// optionally delivering a signal specified by `sig`.
++pub fn syscall<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
++    let data = match sig.into() {
++        Some(s) => s as i32 as *mut c_void,
++        None => ptr::null_mut(),
++    };
+     unsafe {
+         ptrace_other(
+             Request::PTRACE_SYSCALL,
+             pid,
+             ptr::null_mut(),
+-            ptr::null_mut(),
++            data,
+         ).map(drop) // ignore the useless return value
+     }
+ }
+ 
++/// Continue execution until the next syscall, as with `ptrace(PTRACE_SYSEMU, ...)`
++///
++/// In contrast to the `syscall` function, the syscall stopped at will not be executed.
++/// Thus the the tracee will only be stopped once per syscall,
++/// optionally delivering a signal specified by `sig`.
++#[cfg(all(target_os = "linux", target_env = "gnu", any(target_arch = "x86", target_arch = "x86_64")))]
++pub fn sysemu<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
++    let data = match sig.into() {
++        Some(s) => s as i32 as *mut c_void,
++        None => ptr::null_mut(),
++    };
++    unsafe {
++        ptrace_other(Request::PTRACE_SYSEMU, pid, ptr::null_mut(), data).map(drop)
++        // ignore the useless return value
++    }
++}
++
+ /// Attach to a running process, as with `ptrace(PTRACE_ATTACH, ...)`
+ ///
+-/// Attaches to the process specified in pid, making it a tracee of the calling process.
++/// Attaches to the process specified by `pid`, making it a tracee of the calling process.
+ pub fn attach(pid: Pid) -> Result<()> {
+     unsafe {
+         ptrace_other(
+@@ -316,16 +334,36 @@ pub fn attach(pid: Pid) -> Result<()> {
+     }
+ }
+ 
++/// Attach to a running process, as with `ptrace(PTRACE_SEIZE, ...)`
++///
++/// Attaches to the process specified in pid, making it a tracee of the calling process.
++#[cfg(all(target_os = "linux", not(any(target_arch = "mips", target_arch = "mips64"))))]
++pub fn seize(pid: Pid, options: Options) -> Result<()> {
++    unsafe {
++        ptrace_other(
++            Request::PTRACE_SEIZE,
++            pid,
++            ptr::null_mut(),
++            options.bits() as *mut c_void,
++        ).map(drop) // ignore the useless return value
++    }
++}
++
+ /// Detaches the current running process, as with `ptrace(PTRACE_DETACH, ...)`
+ ///
+-/// Detaches from the process specified in pid allowing it to run freely
+-pub fn detach(pid: Pid) -> Result<()> {
++/// Detaches from the process specified by `pid` allowing it to run freely, optionally delivering a
++/// signal specified by `sig`.
++pub fn detach<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
++    let data = match sig.into() {
++        Some(s) => s as i32 as *mut c_void,
++        None => ptr::null_mut(),
++    };
+     unsafe {
+         ptrace_other(
+             Request::PTRACE_DETACH,
+             pid,
+             ptr::null_mut(),
+-            ptr::null_mut()
++            data
+         ).map(drop)
+     }
+ }
+@@ -361,7 +399,6 @@ pub fn kill(pid: Pid) -> Result<()> {
+ ///
+ /// # Example
+ /// ```rust
+-/// extern crate nix;
+ /// use nix::sys::ptrace::step;
+ /// use nix::unistd::Pid;
+ /// use nix::sys::signal::Signal; 
+@@ -388,6 +425,28 @@ pub fn step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
+     }
+ }
+ 
++/// Move the stopped tracee process forward by a single step or stop at the next syscall
++/// as with `ptrace(PTRACE_SYSEMU_SINGLESTEP, ...)`
++///
++/// Advances the execution by a single step or until the next syscall.
++/// In case the tracee is stopped at a syscall, the syscall will not be executed.
++/// Optionally, the signal specified by `sig` is delivered to the tracee upon continuation.
++#[cfg(all(target_os = "linux", target_env = "gnu", any(target_arch = "x86", target_arch = "x86_64")))]
++pub fn sysemu_step<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()> {
++    let data = match sig.into() {
++        Some(s) => s as i32 as *mut c_void,
++        None => ptr::null_mut(),
++    };
++    unsafe {
++        ptrace_other(
++            Request::PTRACE_SYSEMU_SINGLESTEP,
++            pid,
++            ptr::null_mut(),
++            data,
++        )
++        .map(drop) // ignore the useless return value
++    }
++}
+ 
+ /// Reads a word from a processes memory at the given address
+ pub fn read(pid: Pid, addr: AddressType) -> Result<c_long> {
+@@ -395,8 +454,15 @@ pub fn read(pid: Pid, addr: AddressType) -> Result<c_long> {
+ }
+ 
+ /// Writes a word into the processes memory at the given address
+-pub fn write(pid: Pid, addr: AddressType, data: *mut c_void) -> Result<()> {
+-    unsafe {
+-        ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop)
+-    }
++///
++/// # Safety
++///
++/// The `data` argument is passed directly to `ptrace(2)`.  Read that man page
++/// for guidance.
++pub unsafe fn write(
++    pid: Pid,
++    addr: AddressType,
++    data: *mut c_void) -> Result<()>
++{
++    ptrace_other(Request::PTRACE_POKEDATA, pid, addr, data).map(drop)
+ }
+diff --git a/third_party/rust/nix/src/sys/quota.rs b/third_party/rust/nix/src/sys/quota.rs
+index 8946fca2213c8..1933013219102 100644
+--- a/third_party/rust/nix/src/sys/quota.rs
++++ b/third_party/rust/nix/src/sys/quota.rs
+@@ -15,12 +15,13 @@
+ use std::default::Default;
+ use std::{mem, ptr};
+ use libc::{self, c_int, c_char};
+-use {Result, NixPath};
+-use errno::Errno;
++use crate::{Result, NixPath};
++use crate::errno::Errno;
+ 
+ struct QuotaCmd(QuotaSubCmd, QuotaType);
+ 
+ impl QuotaCmd {
++    #[allow(unused_unsafe)]
+     fn as_int(&self) -> c_int {
+         unsafe { libc::QCMD(self.0 as i32, self.1 as i32) }
+     }
+@@ -94,8 +95,7 @@ libc_bitflags!(
+ );
+ 
+ /// Wrapper type for `if_dqblk`
+-// FIXME: Change to repr(transparent)
+-#[repr(C)]
++#[repr(transparent)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+ pub struct Dqblk(libc::dqblk);
+ 
+@@ -254,15 +254,17 @@ pub fn quotactl_off<P: ?Sized + NixPath>(which: QuotaType, special: &P) -> Resul
+ }
+ 
+ /// Update the on-disk copy of quota usages for a filesystem.
++///
++/// If `special` is `None`, then all file systems with active quotas are sync'd.
+ pub fn quotactl_sync<P: ?Sized + NixPath>(which: QuotaType, special: Option<&P>) -> Result<()> {
+     quotactl(QuotaCmd(QuotaSubCmd::Q_SYNC, which), special, 0, ptr::null_mut())
+ }
+ 
+ /// Get disk quota limits and current usage for the given user/group id.
+ pub fn quotactl_get<P: ?Sized + NixPath>(which: QuotaType, special: &P, id: c_int) -> Result<Dqblk> {
+-    let mut dqblk = unsafe { mem::uninitialized() };
+-    quotactl(QuotaCmd(QuotaSubCmd::Q_GETQUOTA, which), Some(special), id, &mut dqblk as *mut _ as *mut c_char)?;
+-    dqblk
++    let mut dqblk = mem::MaybeUninit::uninit();
++    quotactl(QuotaCmd(QuotaSubCmd::Q_GETQUOTA, which), Some(special), id, dqblk.as_mut_ptr() as *mut c_char)?;
++    Ok(unsafe{ Dqblk(dqblk.assume_init())})
+ }
+ 
+ /// Configure quota values for the specified fields for a given user/group id.
+diff --git a/third_party/rust/nix/src/sys/reboot.rs b/third_party/rust/nix/src/sys/reboot.rs
+index bafa8fc11996d..e319130698e82 100644
+--- a/third_party/rust/nix/src/sys/reboot.rs
++++ b/third_party/rust/nix/src/sys/reboot.rs
+@@ -1,9 +1,9 @@
+ //! Reboot/shutdown or enable/disable Ctrl-Alt-Delete.
+ 
+-use {Error, Result};
+-use errno::Errno;
++use crate::{Error, Result};
++use crate::errno::Errno;
+ use libc;
+-use void::Void;
++use std::convert::Infallible;
+ use std::mem::drop;
+ 
+ libc_enum! {
+@@ -22,7 +22,7 @@ libc_enum! {
+     }
+ }
+ 
+-pub fn reboot(how: RebootMode) -> Result<Void> {
++pub fn reboot(how: RebootMode) -> Result<Infallible> {
+     unsafe {
+         libc::reboot(how as libc::c_int)
+     };
+diff --git a/third_party/rust/nix/src/sys/select.rs b/third_party/rust/nix/src/sys/select.rs
+index 1b518e29f67a6..a576c7e4929c4 100644
+--- a/third_party/rust/nix/src/sys/select.rs
++++ b/third_party/rust/nix/src/sys/select.rs
+@@ -1,24 +1,27 @@
++use std::iter::FusedIterator;
+ use std::mem;
++use std::ops::Range;
+ use std::os::unix::io::RawFd;
+ use std::ptr::{null, null_mut};
+ use libc::{self, c_int};
+-use Result;
+-use errno::Errno;
+-use sys::signal::SigSet;
+-use sys::time::{TimeSpec, TimeVal};
++use crate::Result;
++use crate::errno::Errno;
++use crate::sys::signal::SigSet;
++use crate::sys::time::{TimeSpec, TimeVal};
+ 
+ pub use libc::FD_SETSIZE;
+ 
+-// FIXME: Change to repr(transparent) once it's stable
+-#[repr(C)]
++#[repr(transparent)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+ pub struct FdSet(libc::fd_set);
+ 
+ impl FdSet {
+     pub fn new() -> FdSet {
+-        let mut fdset = unsafe { mem::uninitialized() };
+-        unsafe { libc::FD_ZERO(&mut fdset) };
+-        FdSet(fdset)
++        let mut fdset = mem::MaybeUninit::uninit();
++        unsafe {
++            libc::FD_ZERO(fdset.as_mut_ptr());
++            FdSet(fdset.assume_init())
++        }
+     }
+ 
+     pub fn insert(&mut self, fd: RawFd) {
+@@ -46,7 +49,6 @@ impl FdSet {
+     /// # Example
+     ///
+     /// ```
+-    /// # extern crate nix;
+     /// # use nix::sys::select::FdSet;
+     /// # fn main() {
+     /// let mut set = FdSet::new();
+@@ -58,17 +60,81 @@ impl FdSet {
+     ///
+     /// [`select`]: fn.select.html
+     pub fn highest(&mut self) -> Option<RawFd> {
+-        for i in (0..FD_SETSIZE).rev() {
+-            let i = i as RawFd;
+-            if unsafe { libc::FD_ISSET(i, self as *mut _ as *mut libc::fd_set) } {
+-                return Some(i)
++        self.fds(None).next_back()
++    }
++
++    /// Returns an iterator over the file descriptors in the set.
++    /// 
++    /// For performance, it takes an optional higher bound: the iterator will
++    /// not return any elements of the set greater than the given file
++    /// descriptor.
++    ///
++    /// # Examples
++    ///
++    /// ```
++    /// # use nix::sys::select::FdSet;
++    /// # use std::os::unix::io::RawFd;
++    /// let mut set = FdSet::new();
++    /// set.insert(4);
++    /// set.insert(9);
++    /// let fds: Vec<RawFd> = set.fds(None).collect();
++    /// assert_eq!(fds, vec![4, 9]);
++    /// ```
++    #[inline]
++    pub fn fds(&mut self, highest: Option<RawFd>) -> Fds {
++        Fds {
++            set: self,
++            range: 0..highest.map(|h| h as usize + 1).unwrap_or(FD_SETSIZE),
++        }
++    }
++}
++
++impl Default for FdSet {
++    fn default() -> Self {
++        Self::new()
++    }
++}
++
++/// Iterator over `FdSet`.
++#[derive(Debug)]
++pub struct Fds<'a> {
++    set: &'a mut FdSet,
++    range: Range<usize>,
++}
++
++impl<'a> Iterator for Fds<'a> {
++    type Item = RawFd;
++
++    fn next(&mut self) -> Option<RawFd> {
++        while let Some(i) = self.range.next() {
++            if self.set.contains(i as RawFd) {
++                return Some(i as RawFd);
+             }
+         }
++        None
++    }
++
++    #[inline]
++    fn size_hint(&self) -> (usize, Option<usize>) {
++        let (_, upper) = self.range.size_hint();
++        (0, upper)
++    }
++}
+ 
++impl<'a> DoubleEndedIterator for Fds<'a> {
++    #[inline]
++    fn next_back(&mut self) -> Option<RawFd> {
++        while let Some(i) = self.range.next_back() {
++            if self.set.contains(i as RawFd) {
++                return Some(i as RawFd);
++            }
++        }
+         None
+     }
+ }
+ 
++impl<'a> FusedIterator for Fds<'a> {}
++
+ /// Monitors file descriptors for readiness
+ ///
+ /// Returns the total number of ready file descriptors in all sets. The sets are changed so that all
+@@ -93,9 +159,9 @@ impl FdSet {
+ ///
+ /// [`FdSet::highest`]: struct.FdSet.html#method.highest
+ pub fn select<'a, N, R, W, E, T>(nfds: N,
+-                                 readfds: R,
+-                                 writefds: W,
+-                                 errorfds: E,
++    readfds: R,
++    writefds: W,
++    errorfds: E,
+                                  timeout: T) -> Result<c_int>
+ where
+     N: Into<Option<c_int>>,
+@@ -122,7 +188,7 @@ where
+     let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
+     let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
+     let timeout = timeout.map(|tv| tv as *mut _ as *mut libc::timeval)
+-                         .unwrap_or(null_mut());
++        .unwrap_or(null_mut());
+ 
+     let res = unsafe {
+         libc::select(nfds, readfds, writefds, errorfds, timeout)
+@@ -161,10 +227,10 @@ where
+ ///
+ /// [`FdSet::highest`]: struct.FdSet.html#method.highest
+ pub fn pselect<'a, N, R, W, E, T, S>(nfds: N,
+-                                     readfds: R,
+-                                     writefds: W,
+-                                     errorfds: E,
+-                                     timeout: T,
++    readfds: R,
++    writefds: W,
++    errorfds: E,
++    timeout: T,
+                                      sigmask: S) -> Result<c_int>
+ where
+     N: Into<Option<c_int>>,
+@@ -207,8 +273,8 @@ where
+ mod tests {
+     use super::*;
+     use std::os::unix::io::RawFd;
+-    use sys::time::{TimeVal, TimeValLike};
+-    use unistd::{write, pipe};
++    use crate::sys::time::{TimeVal, TimeValLike};
++    use crate::unistd::{write, pipe};
+ 
+     #[test]
+     fn fdset_insert() {
+@@ -272,6 +338,20 @@ mod tests {
+         assert_eq!(set.highest(), Some(7));
+     }
+ 
++    #[test]
++    fn fdset_fds() {
++        let mut set = FdSet::new();
++        assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![]);
++        set.insert(0);
++        assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![0]);
++        set.insert(90);
++        assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![0, 90]);
++
++        // highest limit
++        assert_eq!(set.fds(Some(89)).collect::<Vec<_>>(), vec![0]);
++        assert_eq!(set.fds(Some(90)).collect::<Vec<_>>(), vec![0, 90]);
++    }
++
+     #[test]
+     fn test_select() {
+         let (r1, w1) = pipe().unwrap();
+@@ -304,9 +384,9 @@ mod tests {
+ 
+         let mut timeout = TimeVal::seconds(10);
+         assert_eq!(1, select(Some(fd_set.highest().unwrap() + 1),
+-                             &mut fd_set,
+-                             None,
+-                             None,
++                &mut fd_set,
++                None,
++                None,
+                              &mut timeout).unwrap());
+         assert!(fd_set.contains(r1));
+         assert!(!fd_set.contains(r2));
+@@ -324,9 +404,9 @@ mod tests {
+ 
+         let mut timeout = TimeVal::seconds(10);
+         assert_eq!(1, select(::std::cmp::max(r1, r2) + 1,
+-                             &mut fd_set,
+-                             None,
+-                             None,
++                &mut fd_set,
++                None,
++                None,
+                              &mut timeout).unwrap());
+         assert!(fd_set.contains(r1));
+         assert!(!fd_set.contains(r2));
+diff --git a/third_party/rust/nix/src/sys/sendfile.rs b/third_party/rust/nix/src/sys/sendfile.rs
+index a47d8962f73fb..84fe2a919e8b4 100644
+--- a/third_party/rust/nix/src/sys/sendfile.rs
++++ b/third_party/rust/nix/src/sys/sendfile.rs
+@@ -1,10 +1,11 @@
++use cfg_if::cfg_if;
+ use std::os::unix::io::RawFd;
+ use std::ptr;
+ 
+ use libc::{self, off_t};
+ 
+-use Result;
+-use errno::Errno;
++use crate::Result;
++use crate::errno::Errno;
+ 
+ /// Copy up to `count` bytes to `out_fd` from `in_fd` starting at `offset`.
+ ///
+@@ -36,7 +37,7 @@ cfg_if! {
+     if #[cfg(any(target_os = "freebsd",
+                  target_os = "ios",
+                  target_os = "macos"))] {
+-        use sys::uio::IoVec;
++        use crate::sys::uio::IoVec;
+ 
+         #[derive(Clone, Debug, Eq, Hash, PartialEq)]
+         struct SendfileHeaderTrailer<'a>(
+@@ -123,6 +124,7 @@ cfg_if! {
+         ///
+         /// For more information, see
+         /// [the sendfile(2) man page.](https://www.freebsd.org/cgi/man.cgi?query=sendfile&sektion=2)
++        #[allow(clippy::too_many_arguments)]
+         pub fn sendfile(
+             in_fd: RawFd,
+             out_sock: RawFd,
+@@ -136,7 +138,8 @@ cfg_if! {
+             // Readahead goes in upper 16 bits
+             // Flags goes in lower 16 bits
+             // see `man 2 sendfile`
+-            let flags: u32 = ((readahead as u32) << 16) | (flags.bits() as u32);
++            let ra32 = u32::from(readahead);
++            let flags: u32 = (ra32 << 16) | (flags.bits() as u32);
+             let mut bytes_sent: off_t = 0;
+             let hdtr = headers.or(trailers).map(|_| SendfileHeaderTrailer::new(headers, trailers));
+             let hdtr_ptr = hdtr.as_ref().map_or(ptr::null(), |s| &s.0 as *const libc::sf_hdtr);
+diff --git a/third_party/rust/nix/src/sys/signal.rs b/third_party/rust/nix/src/sys/signal.rs
+index 1013a77fd4b40..2f8b5fa88823d 100644
+--- a/third_party/rust/nix/src/sys/signal.rs
++++ b/third_party/rust/nix/src/sys/signal.rs
+@@ -3,9 +3,10 @@
+ 
+ ///! Operating system signals.
+ 
+-use libc;
+-use {Error, Result};
+-use errno::Errno;
++use crate::{Error, Result};
++use crate::errno::Errno;
++use crate::unistd::Pid;
++use std::convert::TryFrom;
+ use std::mem;
+ use std::fmt;
+ use std::str::FromStr;
+@@ -13,7 +14,7 @@ use std::str::FromStr;
+ use std::os::unix::io::RawFd;
+ use std::ptr;
+ 
+-#[cfg(not(target_os = "openbsd"))]
++#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
+ pub use self::sigevent::*;
+ 
+ libc_enum!{
+@@ -38,8 +39,10 @@ libc_enum!{
+         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,
+@@ -54,12 +57,17 @@ libc_enum!{
+         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")))]
++        #[cfg(not(any(target_os = "android", target_os = "emscripten",
++                      target_os = "fuchsia", target_os = "linux",
++                      target_os = "redox")))]
+         SIGEMT,
+-        #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
++        #[cfg(not(any(target_os = "android", target_os = "emscripten",
++                      target_os = "fuchsia", target_os = "linux",
++                      target_os = "redox")))]
+         SIGINFO,
+     }
+ }
+@@ -83,8 +91,10 @@ impl FromStr for Signal {
+             "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,
+@@ -99,21 +109,31 @@ impl FromStr for Signal {
+             "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")))]
++            #[cfg(not(any(target_os = "android", target_os = "emscripten",
++                          target_os = "fuchsia", target_os = "linux",
++                          target_os = "redox")))]
+             "SIGEMT" => Signal::SIGEMT,
+-            #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
++            #[cfg(not(any(target_os = "android", target_os = "emscripten",
++                          target_os = "fuchsia", target_os = "linux",
++                          target_os = "redox")))]
+             "SIGINFO" => Signal::SIGINFO,
+             _ => return Err(Error::invalid_argument()),
+         })
+     }
+ }
+ 
+-impl AsRef<str> for Signal {
+-    fn as_ref(&self) -> &str {
+-        match *self {
++impl Signal {
++    /// Returns name of signal.
++    ///
++    /// This function is equivalent to `<Signal as AsRef<str>>::as_ref()`,
++    /// with difference that returned string is `'static`
++    /// and not bound to `self`'s lifetime.
++    pub fn as_str(self) -> &'static str {
++        match self {
+             Signal::SIGHUP => "SIGHUP",
+             Signal::SIGINT => "SIGINT",
+             Signal::SIGQUIT => "SIGQUIT",
+@@ -129,7 +149,8 @@ impl AsRef<str> for Signal {
+             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",
+@@ -145,17 +166,28 @@ impl AsRef<str> for Signal {
+             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")))]
++            #[cfg(not(any(target_os = "android", target_os = "emscripten",
++                          target_os = "fuchsia", target_os = "linux",
++                          target_os = "redox")))]
+             Signal::SIGEMT => "SIGEMT",
+-            #[cfg(not(any(target_os = "android", target_os = "emscripten", target_os = "linux")))]
++            #[cfg(not(any(target_os = "android", target_os = "emscripten",
++                          target_os = "fuchsia", target_os = "linux",
++                          target_os = "redox")))]
+             Signal::SIGINFO => "SIGINFO",
+         }
+     }
+ }
+ 
++impl AsRef<str> for Signal {
++    fn as_ref(&self) -> &str {
++        self.as_str()
++    }
++}
++
+ impl fmt::Display for Signal {
+     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+         f.write_str(self.as_ref())
+@@ -164,7 +196,41 @@ impl fmt::Display for Signal {
+ 
+ pub use self::Signal::*;
+ 
+-#[cfg(all(any(target_os = "linux", target_os = "android", target_os = "emscripten"), not(any(target_arch = "mips", target_arch = "mips64", target_arch = "sparc64"))))]
++#[cfg(target_os = "redox")]
++const SIGNALS: [Signal; 29] = [
++    SIGHUP,
++    SIGINT,
++    SIGQUIT,
++    SIGILL,
++    SIGTRAP,
++    SIGABRT,
++    SIGBUS,
++    SIGFPE,
++    SIGKILL,
++    SIGUSR1,
++    SIGSEGV,
++    SIGUSR2,
++    SIGPIPE,
++    SIGALRM,
++    SIGTERM,
++    SIGCHLD,
++    SIGCONT,
++    SIGSTOP,
++    SIGTSTP,
++    SIGTTIN,
++    SIGTTOU,
++    SIGURG,
++    SIGXCPU,
++    SIGXFSZ,
++    SIGVTALRM,
++    SIGPROF,
++    SIGWINCH,
++    SIGIO,
++    SIGSYS];
++#[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,
+@@ -197,7 +263,10 @@ const SIGNALS: [Signal; 31] = [
+     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,
+@@ -229,7 +298,9 @@ const SIGNALS: [Signal; 30] = [
+     SIGIO,
+     SIGPWR,
+     SIGSYS];
+-#[cfg(not(any(target_os = "linux", target_os = "android", target_os = "emscripten")))]
++#[cfg(not(any(target_os = "linux", target_os = "android",
++              target_os = "fuchsia", target_os = "emscripten",
++              target_os = "redox")))]
+ const SIGNALS: [Signal; 31] = [
+     SIGHUP,
+     SIGINT,
+@@ -288,12 +359,12 @@ impl Signal {
+     pub fn iterator() -> SignalIterator {
+         SignalIterator{next: 0}
+     }
++}
++
++impl TryFrom<libc::c_int> for Signal {
++    type Error = Error;
+ 
+-    // We do not implement the From trait, because it is supposed to be infallible.
+-    // With Rust RFC 1542 comes the appropriate trait TryFrom. Once it is
+-    // implemented, we'll replace this function.
+-    #[inline]
+-    pub fn from_c_int(signum: libc::c_int) -> Result<Signal> {
++    fn try_from(signum: libc::c_int) -> Result<Signal> {
+         if 0 < signum && signum < NSIG {
+             Ok(unsafe { mem::transmute(signum) })
+         } else {
+@@ -306,8 +377,13 @@ pub const SIGIOT : Signal = SIGABRT;
+ pub const SIGPOLL : Signal = SIGIO;
+ pub const SIGUNUSED : Signal = SIGSYS;
+ 
++#[cfg(not(target_os = "redox"))]
++type SaFlags_t = libc::c_int;
++#[cfg(target_os = "redox")]
++type SaFlags_t = libc::c_ulong;
++
+ libc_bitflags!{
+-    pub struct SaFlags: libc::c_int {
++    pub struct SaFlags: SaFlags_t {
+         SA_NOCLDSTOP;
+         SA_NOCLDWAIT;
+         SA_NODEFER;
+@@ -335,17 +411,17 @@ pub struct SigSet {
+ 
+ impl SigSet {
+     pub fn all() -> SigSet {
+-        let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
+-        let _ = unsafe { libc::sigfillset(&mut sigset as *mut libc::sigset_t) };
++        let mut sigset = mem::MaybeUninit::uninit();
++        let _ = unsafe { libc::sigfillset(sigset.as_mut_ptr()) };
+ 
+-        SigSet { sigset: sigset }
++        unsafe{ SigSet { sigset: sigset.assume_init() } }
+     }
+ 
+     pub fn empty() -> SigSet {
+-        let mut sigset: libc::sigset_t = unsafe { mem::uninitialized() };
+-        let _ = unsafe { libc::sigemptyset(&mut sigset as *mut libc::sigset_t) };
++        let mut sigset = mem::MaybeUninit::uninit();
++        let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) };
+ 
+-        SigSet { sigset: sigset }
++        unsafe{ SigSet { sigset: sigset.assume_init() } }
+     }
+ 
+     pub fn add(&mut self, signal: Signal) {
+@@ -380,9 +456,9 @@ impl SigSet {
+ 
+     /// Gets the currently blocked (masked) set of signals for the calling thread.
+     pub fn thread_get_mask() -> Result<SigSet> {
+-        let mut oldmask: SigSet = unsafe { mem::uninitialized() };
+-        pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(&mut oldmask))?;
+-        Ok(oldmask)
++        let mut oldmask = mem::MaybeUninit::uninit();
++        do_pthread_sigmask(SigmaskHow::SIG_SETMASK, None, Some(oldmask.as_mut_ptr()))?;
++        Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
+     }
+ 
+     /// Sets the set of signals as the signal mask for the calling thread.
+@@ -402,18 +478,21 @@ impl SigSet {
+ 
+     /// Sets the set of signals as the signal mask, and returns the old mask.
+     pub fn thread_swap_mask(&self, how: SigmaskHow) -> Result<SigSet> {
+-        let mut oldmask: SigSet = unsafe { mem::uninitialized() };
+-        pthread_sigmask(how, Some(self), Some(&mut oldmask))?;
+-        Ok(oldmask)
++        let mut oldmask = mem::MaybeUninit::uninit();
++        do_pthread_sigmask(how, Some(self), Some(oldmask.as_mut_ptr()))?;
++        Ok(unsafe{ SigSet{sigset: oldmask.assume_init()}})
+     }
+ 
+     /// Suspends execution of the calling thread until one of the signals in the
+     /// signal mask becomes pending, and returns the accepted signal.
++    #[cfg(not(target_os = "redox"))] // RedoxFS does not yet support sigwait
+     pub fn wait(&self) -> Result<Signal> {
+-        let mut signum: libc::c_int = unsafe { mem::uninitialized() };
+-        let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, &mut signum) };
++        let mut signum = mem::MaybeUninit::uninit();
++        let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) };
+ 
+-        Errno::result(res).map(|_| Signal::from_c_int(signum).unwrap())
++        Errno::result(res).map(|_| unsafe {
++            Signal::try_from(signum.assume_init()).unwrap()
++        })
+     }
+ }
+ 
+@@ -435,6 +514,7 @@ pub enum SigHandler {
+     Handler(extern fn(libc::c_int)),
+     /// Use the given signal-catching function, which takes in the signal, information about how
+     /// the signal was generated, and a pointer to the threads `ucontext_t`.
++    #[cfg(not(target_os = "redox"))]
+     SigAction(extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void))
+ }
+ 
+@@ -451,20 +531,38 @@ impl SigAction {
+     /// is the `SigAction` variant). `mask` specifies other signals to block during execution of
+     /// the signal-catching function.
+     pub fn new(handler: SigHandler, flags: SaFlags, mask: SigSet) -> SigAction {
+-        let mut s = unsafe { mem::uninitialized::<libc::sigaction>() };
+-        s.sa_sigaction = match handler {
+-            SigHandler::SigDfl => libc::SIG_DFL,
+-            SigHandler::SigIgn => libc::SIG_IGN,
+-            SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
+-            SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
+-        };
+-        s.sa_flags = match handler {
+-            SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(),
+-            _ => (flags - SaFlags::SA_SIGINFO).bits(),
+-        };
+-        s.sa_mask = mask.sigset;
+-
+-        SigAction { sigaction: s }
++        #[cfg(target_os = "redox")]
++        unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
++            (*p).sa_handler = match handler {
++                SigHandler::SigDfl => libc::SIG_DFL,
++                SigHandler::SigIgn => libc::SIG_IGN,
++                SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
++            };
++        }
++
++        #[cfg(not(target_os = "redox"))]
++        unsafe fn install_sig(p: *mut libc::sigaction, handler: SigHandler) {
++            (*p).sa_sigaction = match handler {
++                SigHandler::SigDfl => libc::SIG_DFL,
++                SigHandler::SigIgn => libc::SIG_IGN,
++                SigHandler::Handler(f) => f as *const extern fn(libc::c_int) as usize,
++                SigHandler::SigAction(f) => f as *const extern fn(libc::c_int, *mut libc::siginfo_t, *mut libc::c_void) as usize,
++            };
++        }
++
++        let mut s = mem::MaybeUninit::<libc::sigaction>::uninit();
++        unsafe {
++            let p = s.as_mut_ptr();
++            install_sig(p, handler);
++            (*p).sa_flags = match handler {
++                #[cfg(not(target_os = "redox"))]
++                SigHandler::SigAction(_) => (flags | SaFlags::SA_SIGINFO).bits(),
++                _ => (flags - SaFlags::SA_SIGINFO).bits(),
++            };
++            (*p).sa_mask = mask.sigset;
++
++            SigAction { sigaction: s.assume_init() }
++        }
+     }
+ 
+     /// Returns the flags set on the action.
+@@ -479,6 +577,7 @@ impl SigAction {
+     }
+ 
+     /// Returns the action's handler.
++    #[cfg(not(target_os = "redox"))]
+     pub fn handler(&self) -> SigHandler {
+         match self.sigaction.sa_sigaction {
+             libc::SIG_DFL => SigHandler::SigDfl,
+@@ -488,6 +587,16 @@ impl SigAction {
+             f => SigHandler::Handler( unsafe { mem::transmute(f) } ),
+         }
+     }
++
++    /// Returns the action's handler.
++    #[cfg(target_os = "redox")]
++    pub fn handler(&self) -> SigHandler {
++        match self.sigaction.sa_handler {
++            libc::SIG_DFL => SigHandler::SigDfl,
++            libc::SIG_IGN => SigHandler::SigIgn,
++            f => SigHandler::Handler( unsafe { mem::transmute(f) } ),
++        }
++    }
+ }
+ 
+ /// Changes the action taken by a process on receipt of a specific signal.
+@@ -501,12 +610,13 @@ impl SigAction {
+ /// the body of the signal-catching function. Be certain to only make syscalls that are explicitly
+ /// marked safe for signal handlers and only share global data using atomics.
+ pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigAction> {
+-    let mut oldact = mem::uninitialized::<libc::sigaction>();
++    let mut oldact = mem::MaybeUninit::<libc::sigaction>::uninit();
+ 
+-    let res =
+-        libc::sigaction(signal as libc::c_int, &sigaction.sigaction as *const libc::sigaction, &mut oldact as *mut libc::sigaction);
++    let res = libc::sigaction(signal as libc::c_int,
++                              &sigaction.sigaction as *const libc::sigaction,
++                              oldact.as_mut_ptr());
+ 
+-    Errno::result(res).map(|_| SigAction { sigaction: oldact })
++    Errno::result(res).map(|_| SigAction { sigaction: oldact.assume_init() })
+ }
+ 
+ /// Signal management (see [signal(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html))
+@@ -534,8 +644,7 @@ pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigActi
+ ///
+ /// ```no_run
+ /// # #[macro_use] extern crate lazy_static;
+-/// # extern crate libc;
+-/// # extern crate nix;
++/// # use std::convert::TryFrom;
+ /// # use std::sync::atomic::{AtomicBool, Ordering};
+ /// # use nix::sys::signal::{self, Signal, SigHandler};
+ /// lazy_static! {
+@@ -543,7 +652,7 @@ pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result<SigActi
+ /// }
+ ///
+ /// extern fn handle_sigint(signal: libc::c_int) {
+-///     let signal = Signal::from_c_int(signal).unwrap();
++///     let signal = Signal::try_from(signal).unwrap();
+ ///     SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed);
+ /// }
+ ///
+@@ -571,6 +680,7 @@ pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler>
+         SigHandler::SigDfl => libc::signal(signal, libc::SIG_DFL),
+         SigHandler::SigIgn => libc::signal(signal, libc::SIG_IGN),
+         SigHandler::Handler(handler) => libc::signal(signal, handler as libc::sighandler_t),
++        #[cfg(not(target_os = "redox"))]
+         SigHandler::SigAction(_) => return Err(Error::UnsupportedOperation),
+     };
+     Errno::result(res).map(|oldhandler| {
+@@ -582,6 +692,25 @@ pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler>
+     })
+ }
+ 
++fn do_pthread_sigmask(how: SigmaskHow,
++                       set: Option<&SigSet>,
++                       oldset: Option<*mut libc::sigset_t>) -> Result<()> {
++    if set.is_none() && oldset.is_none() {
++        return Ok(())
++    }
++
++    let res = unsafe {
++        // if set or oldset is None, pass in null pointers instead
++        libc::pthread_sigmask(how as libc::c_int,
++                             set.map_or_else(ptr::null::<libc::sigset_t>,
++                                             |s| &s.sigset as *const libc::sigset_t),
++                             oldset.unwrap_or(ptr::null_mut())
++                             )
++    };
++
++    Errno::result(res).map(drop)
++}
++
+ /// Manages the signal mask (set of blocked signals) for the calling thread.
+ ///
+ /// If the `set` parameter is `Some(..)`, then the signal mask will be updated with the signal set.
+@@ -599,21 +728,9 @@ pub unsafe fn signal(signal: Signal, handler: SigHandler) -> Result<SigHandler>
+ /// or [`sigprocmask`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/sigprocmask.html) man pages.
+ pub fn pthread_sigmask(how: SigmaskHow,
+                        set: Option<&SigSet>,
+-                       oldset: Option<&mut SigSet>) -> Result<()> {
+-    if set.is_none() && oldset.is_none() {
+-        return Ok(())
+-    }
+-
+-    let res = unsafe {
+-        // if set or oldset is None, pass in null pointers instead
+-        libc::pthread_sigmask(how as libc::c_int,
+-                             set.map_or_else(ptr::null::<libc::sigset_t>,
+-                                             |s| &s.sigset as *const libc::sigset_t),
+-                             oldset.map_or_else(ptr::null_mut::<libc::sigset_t>,
+-                                                |os| &mut os.sigset as *mut libc::sigset_t))
+-    };
+-
+-    Errno::result(res).map(drop)
++                       oldset: Option<&mut SigSet>) -> Result<()>
++{
++    do_pthread_sigmask(how, set, oldset.map(|os| &mut os.sigset as *mut _ ))
+ }
+ 
+ /// Examine and change blocked signals.
+@@ -637,7 +754,7 @@ pub fn sigprocmask(how: SigmaskHow, set: Option<&SigSet>, oldset: Option<&mut Si
+     Errno::result(res).map(drop)
+ }
+ 
+-pub fn kill<T: Into<Option<Signal>>>(pid: ::unistd::Pid, signal: T) -> Result<()> {
++pub fn kill<T: Into<Option<Signal>>>(pid: Pid, signal: T) -> Result<()> {
+     let res = unsafe { libc::kill(pid.into(),
+                                   match signal.into() {
+                                       Some(s) => s as libc::c_int,
+@@ -653,7 +770,8 @@ pub fn kill<T: Into<Option<Signal>>>(pid: ::unistd::Pid, signal: T) -> Result<()
+ /// 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.
+-pub fn killpg<T: Into<Option<Signal>>>(pgrp: ::unistd::Pid, signal: T) -> Result<()> {
++#[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() {
+                                       Some(s) => s as libc::c_int,
+@@ -702,9 +820,8 @@ pub enum SigevNotify {
+                     si_value: libc::intptr_t },
+ }
+ 
+-#[cfg(not(target_os = "openbsd"))]
++#[cfg(not(any(target_os = "openbsd", target_os = "redox")))]
+ mod sigevent {
+-    use libc;
+     use std::mem;
+     use std::ptr;
+     use super::SigevNotify;
+@@ -734,7 +851,10 @@ mod sigevent {
+         /// `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,
+@@ -793,6 +913,7 @@ mod sigevent {
+ 
+ #[cfg(test)]
+ mod tests {
++    #[cfg(not(target_os = "redox"))]
+     use std::thread;
+     use super::*;
+ 
+@@ -848,6 +969,7 @@ mod tests {
+     }
+ 
+     #[test]
++    #[cfg(not(target_os = "redox"))]
+     fn test_thread_signal_set_mask() {
+         thread::spawn(|| {
+             let prev_mask = SigSet::thread_get_mask()
+@@ -868,6 +990,7 @@ mod tests {
+     }
+ 
+     #[test]
++    #[cfg(not(target_os = "redox"))]
+     fn test_thread_signal_block() {
+         thread::spawn(|| {
+             let mut mask = SigSet::empty();
+@@ -880,6 +1003,7 @@ mod tests {
+     }
+ 
+     #[test]
++    #[cfg(not(target_os = "redox"))]
+     fn test_thread_signal_unblock() {
+         thread::spawn(|| {
+             let mut mask = SigSet::empty();
+@@ -892,6 +1016,7 @@ mod tests {
+     }
+ 
+     #[test]
++    #[cfg(not(target_os = "redox"))]
+     fn test_thread_signal_swap() {
+         thread::spawn(|| {
+             let mut mask = SigSet::empty();
+@@ -914,8 +1039,8 @@ mod tests {
+     }
+ 
+     #[test]
++    #[cfg(not(target_os = "redox"))]
+     fn test_sigaction() {
+-        use libc;
+         thread::spawn(|| {
+             extern fn test_sigaction_handler(_: libc::c_int) {}
+             extern fn test_sigaction_action(_: libc::c_int,
+@@ -952,6 +1077,7 @@ mod tests {
+     }
+ 
+     #[test]
++    #[cfg(not(target_os = "redox"))]
+     fn test_sigwait() {
+         thread::spawn(|| {
+             let mut mask = SigSet::empty();
+diff --git a/third_party/rust/nix/src/sys/signalfd.rs b/third_party/rust/nix/src/sys/signalfd.rs
+index 5425a27be9e52..c43b45046f719 100644
+--- a/third_party/rust/nix/src/sys/signalfd.rs
++++ b/third_party/rust/nix/src/sys/signalfd.rs
+@@ -16,10 +16,10 @@
+ //! Please note that signal discarding is not specific to `signalfd`, but also happens with regular
+ //! signal handlers.
+ use libc;
+-use unistd;
+-use {Error, Result};
+-use errno::Errno;
+-pub use sys::signal::{self, SigSet};
++use crate::unistd;
++use crate::{Error, Result};
++use crate::errno::Errno;
++pub use crate::sys::signal::{self, SigSet};
+ pub use libc::signalfd_siginfo as siginfo;
+ 
+ use std::os::unix::io::{RawFd, AsRawFd};
+@@ -79,7 +79,7 @@ pub fn signalfd(fd: RawFd, mask: &SigSet, flags: SfdFlags) -> Result<RawFd> {
+ ///     Err(err) => (), // some error happend
+ /// }
+ /// ```
+-#[derive(Clone, Debug, Eq, Hash, PartialEq)]
++#[derive(Debug, Eq, Hash, PartialEq)]
+ pub struct SignalFd(RawFd);
+ 
+ impl SignalFd {
+@@ -98,10 +98,15 @@ impl SignalFd {
+     }
+ 
+     pub fn read_signal(&mut self) -> Result<Option<siginfo>> {
+-        let mut buffer: [u8; SIGNALFD_SIGINFO_SIZE] = unsafe { mem::uninitialized() };
+-
+-        match unistd::read(self.0, &mut buffer) {
+-            Ok(SIGNALFD_SIGINFO_SIZE) => Ok(Some(unsafe { mem::transmute(buffer) })),
++        let mut buffer = mem::MaybeUninit::<[u8; SIGNALFD_SIGINFO_SIZE]>::uninit();
++
++        let res = Errno::result(unsafe {
++            libc::read(self.0,
++                       buffer.as_mut_ptr() as *mut libc::c_void,
++                       SIGNALFD_SIGINFO_SIZE as libc::size_t)
++        }).map(|r| r as usize);
++        match res {
++            Ok(SIGNALFD_SIGINFO_SIZE) => Ok(Some(unsafe { mem::transmute(buffer.assume_init()) })),
+             Ok(_) => unreachable!("partial read on signalfd"),
+             Err(Error::Sys(Errno::EAGAIN)) => Ok(None),
+             Err(error) => Err(error)
+@@ -111,7 +116,10 @@ impl SignalFd {
+ 
+ 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/third_party/rust/nix/src/sys/socket/addr.rs b/third_party/rust/nix/src/sys/socket/addr.rs
+index ed41441155361..5a2739bd10194 100644
+--- a/third_party/rust/nix/src/sys/socket/addr.rs
++++ b/third_party/rust/nix/src/sys/socket/addr.rs
+@@ -1,20 +1,20 @@
+ use super::sa_family_t;
+-use {Error, Result, NixPath};
+-use errno::Errno;
+-use libc;
++use crate::{Error, Result, NixPath};
++use crate::errno::Errno;
++use memoffset::offset_of;
+ use std::{fmt, mem, net, ptr, slice};
+ use std::ffi::OsStr;
+ use std::hash::{Hash, Hasher};
+ use std::path::Path;
+ use std::os::unix::ffi::OsStrExt;
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+-use ::sys::socket::addr::netlink::NetlinkAddr;
++use crate::sys::socket::addr::netlink::NetlinkAddr;
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+-use ::sys::socket::addr::alg::AlgAddr;
++use crate::sys::socket::addr::alg::AlgAddr;
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ use std::os::unix::io::RawFd;
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+-use ::sys::socket::addr::sys_control::SysControlAddr;
++use crate::sys::socket::addr::sys_control::SysControlAddr;
+ #[cfg(any(target_os = "android",
+           target_os = "dragonfly",
+           target_os = "freebsd",
+@@ -22,9 +22,10 @@ use ::sys::socket::addr::sys_control::SysControlAddr;
+           target_os = "linux",
+           target_os = "macos",
+           target_os = "netbsd",
+-          target_os = "openbsd"))]
++          target_os = "openbsd",
++          target_os = "fuchsia"))]
+ pub use self::datalink::LinkAddr;
+-#[cfg(target_os = "linux")]
++#[cfg(any(target_os = "android", target_os = "linux"))]
+ pub use self::vsock::VsockAddr;
+ 
+ /// These constants specify the protocol family to be used
+@@ -42,7 +43,7 @@ pub enum AddressFamily {
+     #[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"))]
+@@ -116,7 +117,7 @@ pub enum AddressFamily {
+     Alg = libc::AF_ALG,
+     #[cfg(target_os = "linux")]
+     Nfc = libc::AF_NFC,
+-    #[cfg(target_os = "linux")]
++    #[cfg(any(target_os = "android", target_os = "linux"))]
+     Vsock = libc::AF_VSOCK,
+     #[cfg(any(target_os = "dragonfly",
+               target_os = "freebsd",
+@@ -243,7 +244,7 @@ impl AddressFamily {
+                       target_os = "netbsd",
+                       target_os = "openbsd"))]
+             libc::AF_LINK => Some(AddressFamily::Link),
+-            #[cfg(target_os = "linux")]
++            #[cfg(any(target_os = "android", target_os = "linux"))]
+             libc::AF_VSOCK => Some(AddressFamily::Vsock),
+             _ => None
+         }
+@@ -367,6 +368,8 @@ impl IpAddr {
+     /// Create a new IpAddr that contains an IPv6 address.
+     ///
+     /// The result will represent the IP address a:b:c:d:e:f
++    #[allow(clippy::many_single_char_names)]
++    #[allow(clippy::too_many_arguments)]
+     pub fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> IpAddr {
+         IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h))
+     }
+@@ -405,15 +408,18 @@ impl fmt::Display for IpAddr {
+ pub struct Ipv4Addr(pub libc::in_addr);
+ 
+ impl Ipv4Addr {
++    #[allow(clippy::identity_op)]   // More readable this way
+     pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
+-        let ip = (((a as u32) << 24) |
+-                  ((b as u32) << 16) |
+-                  ((c as u32) <<  8) |
+-                  ((d as u32) <<  0)).to_be();
++        let ip = ((u32::from(a) << 24) |
++                  (u32::from(b) << 16) |
++                  (u32::from(c) <<  8) |
++                  (u32::from(d) <<  0)).to_be();
+ 
+         Ipv4Addr(libc::in_addr { s_addr: ip })
+     }
+ 
++    // Use pass by reference for symmetry with Ipv6Addr::from_std
++    #[allow(clippy::trivially_copy_pass_by_ref)]
+     pub fn from_std(std: &net::Ipv4Addr) -> Ipv4Addr {
+         let bits = std.octets();
+         Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
+@@ -423,12 +429,12 @@ impl Ipv4Addr {
+         Ipv4Addr(libc::in_addr { s_addr: libc::INADDR_ANY })
+     }
+ 
+-    pub fn octets(&self) -> [u8; 4] {
++    pub fn octets(self) -> [u8; 4] {
+         let bits = u32::from_be(self.0.s_addr);
+         [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8]
+     }
+ 
+-    pub fn to_std(&self) -> net::Ipv4Addr {
++    pub fn to_std(self) -> net::Ipv4Addr {
+         let bits = self.octets();
+         net::Ipv4Addr::new(bits[0], bits[1], bits[2], bits[3])
+     }
+@@ -467,10 +473,10 @@ macro_rules! to_u16_array {
+ }
+ 
+ impl Ipv6Addr {
++    #[allow(clippy::many_single_char_names)]
++    #[allow(clippy::too_many_arguments)]
+     pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16, h: u16) -> Ipv6Addr {
+-        let mut in6_addr_var: libc::in6_addr = unsafe{mem::uninitialized()};
+-        in6_addr_var.s6_addr = to_u8_array!(a,b,c,d,e,f,g,h);
+-        Ipv6Addr(in6_addr_var)
++        Ipv6Addr(libc::in6_addr{s6_addr: to_u8_array!(a,b,c,d,e,f,g,h)})
+     }
+ 
+     pub fn from_std(std: &net::Ipv6Addr) -> Ipv6Addr {
+@@ -555,7 +561,7 @@ impl UnixAddr {
+                                      ret.sun_path.as_mut_ptr().offset(1) as *mut u8,
+                                      path.len());
+ 
+-            Ok(UnixAddr(ret, ret.sun_path.len()))
++            Ok(UnixAddr(ret, path.len() + 1))
+         }
+     }
+ 
+@@ -643,7 +649,7 @@ pub enum SockAddr {
+               target_os = "netbsd",
+               target_os = "openbsd"))]
+     Link(LinkAddr),
+-    #[cfg(target_os = "linux")]
++    #[cfg(any(target_os = "android", target_os = "linux"))]
+     Vsock(VsockAddr),
+ }
+ 
+@@ -671,7 +677,7 @@ impl SockAddr {
+         SysControlAddr::from_name(sockfd, name, unit).map(|a| SockAddr::SysControl(a))
+     }
+ 
+-    #[cfg(target_os = "linux")]
++    #[cfg(any(target_os = "android", target_os = "linux"))]
+     pub fn new_vsock(cid: u32, port: u32) -> SockAddr {
+         SockAddr::Vsock(VsockAddr::new(cid, port))
+     }
+@@ -696,7 +702,7 @@ impl SockAddr {
+                       target_os = "netbsd",
+                       target_os = "openbsd"))]
+             SockAddr::Link(..) => AddressFamily::Link,
+-            #[cfg(target_os = "linux")]
++            #[cfg(any(target_os = "android", target_os = "linux"))]
+             SockAddr::Vsock(..) => AddressFamily::Vsock,
+         }
+     }
+@@ -709,11 +715,17 @@ impl SockAddr {
+     ///
+     /// Supports only the following address families: Unix, Inet (v4 & v6), Netlink and System.
+     /// Returns None for unsupported families.
+-    pub unsafe fn from_libc_sockaddr(addr: *const libc::sockaddr) -> Option<SockAddr> {
++    ///
++    /// # Safety
++    ///
++    /// 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
+         } else {
+-            match AddressFamily::from_i32((*addr).sa_family as i32) {
++            match AddressFamily::from_i32(i32::from((*addr).sa_family)) {
+                 Some(AddressFamily::Unix) => None,
+                 Some(AddressFamily::Inet) => Some(SockAddr::Inet(
+                     InetAddr::V4(*(addr as *const libc::sockaddr_in)))),
+@@ -742,7 +754,7 @@ impl SockAddr {
+                         Some(SockAddr::Link(ether_addr))
+                     }
+                 },
+-                #[cfg(target_os = "linux")]
++                #[cfg(any(target_os = "android", target_os = "linux"))]
+                 Some(AddressFamily::Vsock) => Some(SockAddr::Vsock(
+                     VsockAddr(*(addr as *const libc::sockaddr_vm)))),
+                 // Other address families are currently not supported and simply yield a None
+@@ -759,28 +771,83 @@ impl SockAddr {
+     /// with the size of the actual data type. sockaddr is commonly used as a proxy for
+     /// a superclass as C doesn't support inheritance, so many functions that take
+     /// a sockaddr * need to take the size of the underlying type as well and then internally cast it back.
+-    pub unsafe fn as_ffi_pair(&self) -> (&libc::sockaddr, libc::socklen_t) {
++    pub fn as_ffi_pair(&self) -> (&libc::sockaddr, libc::socklen_t) {
+         match *self {
+-            SockAddr::Inet(InetAddr::V4(ref addr)) => (mem::transmute(addr), mem::size_of::<libc::sockaddr_in>() as libc::socklen_t),
+-            SockAddr::Inet(InetAddr::V6(ref addr)) => (mem::transmute(addr), mem::size_of::<libc::sockaddr_in6>() as libc::socklen_t),
+-            SockAddr::Unix(UnixAddr(ref addr, len)) => (mem::transmute(addr), (len + offset_of!(libc::sockaddr_un, sun_path)) as libc::socklen_t),
++            SockAddr::Inet(InetAddr::V4(ref addr)) => (
++                // This cast is always allowed in C
++                unsafe {
++                    &*(addr as *const libc::sockaddr_in as *const libc::sockaddr)
++                },
++                mem::size_of_val(addr) as libc::socklen_t
++            ),
++            SockAddr::Inet(InetAddr::V6(ref addr)) => (
++                // This cast is always allowed in C
++                unsafe {
++                    &*(addr as *const libc::sockaddr_in6 as *const libc::sockaddr)
++                },
++                mem::size_of_val(addr) as libc::socklen_t
++            ),
++            SockAddr::Unix(UnixAddr(ref addr, len)) => (
++                // This cast is always allowed in C
++                unsafe {
++                    &*(addr as *const libc::sockaddr_un as *const libc::sockaddr)
++                },
++                (len + offset_of!(libc::sockaddr_un, sun_path)) as libc::socklen_t
++            ),
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            SockAddr::Netlink(NetlinkAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_nl>() as libc::socklen_t),
++            SockAddr::Netlink(NetlinkAddr(ref sa)) => (
++                // This cast is always allowed in C
++                unsafe {
++                    &*(sa as *const libc::sockaddr_nl as *const libc::sockaddr)
++                },
++                mem::size_of_val(sa) as libc::socklen_t
++            ),
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            SockAddr::Alg(AlgAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_alg>() as libc::socklen_t),
++            SockAddr::Alg(AlgAddr(ref sa)) => (
++                // This cast is always allowed in C
++                unsafe {
++                    &*(sa as *const libc::sockaddr_alg as *const libc::sockaddr)
++                },
++                mem::size_of_val(sa) as libc::socklen_t
++            ),
+             #[cfg(any(target_os = "ios", target_os = "macos"))]
+-            SockAddr::SysControl(SysControlAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_ctl>() as libc::socklen_t),
++            SockAddr::SysControl(SysControlAddr(ref sa)) => (
++                // This cast is always allowed in C
++                unsafe {
++                    &*(sa as *const libc::sockaddr_ctl as *const libc::sockaddr)
++                },
++                mem::size_of_val(sa) as libc::socklen_t
++
++            ),
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            SockAddr::Link(LinkAddr(ref ether_addr)) => (mem::transmute(ether_addr), mem::size_of::<libc::sockaddr_ll>() as libc::socklen_t),
++            SockAddr::Link(LinkAddr(ref addr)) => (
++                // This cast is always allowed in C
++                unsafe {
++                    &*(addr as *const libc::sockaddr_ll as *const libc::sockaddr)
++                },
++                mem::size_of_val(addr) as libc::socklen_t
++            ),
+             #[cfg(any(target_os = "dragonfly",
+                       target_os = "freebsd",
+                       target_os = "ios",
+                       target_os = "macos",
+                       target_os = "netbsd",
+                       target_os = "openbsd"))]
+-            SockAddr::Link(LinkAddr(ref ether_addr)) => (mem::transmute(ether_addr), mem::size_of::<libc::sockaddr_dl>() as libc::socklen_t),
+-            #[cfg(target_os = "linux")]
+-            SockAddr::Vsock(VsockAddr(ref sa)) => (mem::transmute(sa), mem::size_of::<libc::sockaddr_vm>() as libc::socklen_t),
++            SockAddr::Link(LinkAddr(ref addr)) => (
++                // This cast is always allowed in C
++                unsafe {
++                    &*(addr as *const libc::sockaddr_dl as *const libc::sockaddr)
++                },
++                mem::size_of_val(addr) as libc::socklen_t
++            ),
++            #[cfg(any(target_os = "android", target_os = "linux"))]
++            SockAddr::Vsock(VsockAddr(ref sa)) => (
++                // This cast is always allowed in C
++                unsafe {
++                    &*(sa as *const libc::sockaddr_vm as *const libc::sockaddr)
++                },
++                mem::size_of_val(sa) as libc::socklen_t
++            ),
+         }
+     }
+ }
+@@ -805,7 +872,7 @@ impl fmt::Display for SockAddr {
+                       target_os = "netbsd",
+                       target_os = "openbsd"))]
+             SockAddr::Link(ref ether_addr) => ether_addr.fmt(f),
+-            #[cfg(target_os = "linux")]
++            #[cfg(any(target_os = "android", target_os = "linux"))]
+             SockAddr::Vsock(ref svm) => svm.fmt(f),
+         }
+     }
+@@ -813,7 +880,7 @@ impl fmt::Display for SockAddr {
+ 
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ pub mod netlink {
+-    use ::sys::socket::addr::AddressFamily;
++    use crate::sys::socket::addr::AddressFamily;
+     use libc::{sa_family_t, sockaddr_nl};
+     use std::{fmt, mem};
+ 
+@@ -911,11 +978,11 @@ pub mod alg {
+ 
+ #[cfg(any(target_os = "ios", target_os = "macos"))]
+ pub mod sys_control {
+-    use ::sys::socket::addr::AddressFamily;
++    use crate::sys::socket::addr::AddressFamily;
+     use libc::{self, c_uchar};
+     use std::{fmt, mem};
+     use std::os::unix::io::RawFd;
+-    use {Errno, Error, Result};
++    use crate::{Errno, Error, Result};
+ 
+     // FIXME: Move type into `libc`
+     #[repr(C)]
+@@ -957,7 +1024,7 @@ pub mod sys_control {
+ 
+             let mut ctl_name = [0; MAX_KCTL_NAME];
+             ctl_name[..name.len()].clone_from_slice(name.as_bytes());
+-            let mut info = ctl_ioc_info { ctl_id: 0, ctl_name: ctl_name };
++            let mut info = ctl_ioc_info { ctl_id: 0, ctl_name };
+ 
+             unsafe { ctl_info(sockfd, &mut info)?; }
+ 
+@@ -981,9 +1048,9 @@ pub mod sys_control {
+ }
+ 
+ 
+-#[cfg(any(target_os = "android", target_os = "linux"))]
++#[cfg(any(target_os = "android", target_os = "linux", target_os = "fuchsia"))]
+ mod datalink {
+-    use super::{libc, fmt, AddressFamily};
++    use super::{fmt, AddressFamily};
+ 
+     /// Hardware Address
+     #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+@@ -1023,14 +1090,14 @@ mod datalink {
+ 
+         /// Physical-layer address (MAC)
+         pub fn addr(&self) -> [u8; 6] {
+-            let a = self.0.sll_addr[0] as u8;
+-            let b = self.0.sll_addr[1] as u8;
+-            let c = self.0.sll_addr[2] as u8;
+-            let d = self.0.sll_addr[3] as u8;
+-            let e = self.0.sll_addr[4] as u8;
+-            let f = self.0.sll_addr[5] as u8;
+-
+-            [a, b, c, d, e, f]
++            [
++                self.0.sll_addr[0] as u8,
++                self.0.sll_addr[1] as u8,
++                self.0.sll_addr[2] as u8,
++                self.0.sll_addr[3] as u8,
++                self.0.sll_addr[4] as u8,
++                self.0.sll_addr[5] as u8,
++            ]
+         }
+     }
+ 
+@@ -1055,7 +1122,7 @@ mod datalink {
+           target_os = "netbsd",
+           target_os = "openbsd"))]
+ mod datalink {
+-    use super::{libc, fmt, AddressFamily};
++    use super::{fmt, AddressFamily};
+ 
+     /// Hardware Address
+     #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+@@ -1069,7 +1136,7 @@ mod datalink {
+ 
+         /// always == AF_LINK
+         pub fn family(&self) -> AddressFamily {
+-            assert_eq!(self.0.sdl_family as i32, libc::AF_LINK);
++            assert_eq!(i32::from(self.0.sdl_family), libc::AF_LINK);
+             AddressFamily::Link
+         }
+ 
+@@ -1105,11 +1172,7 @@ mod datalink {
+             let alen = self.alen();
+             let data_len = self.0.sdl_data.len();
+ 
+-            if alen > 0 && nlen + alen < data_len {
+-                false
+-            } else {
+-                true
+-            }
++            alen == 0 || nlen + alen >= data_len
+         }
+ 
+         /// Physical-layer address (MAC)
+@@ -1119,14 +1182,14 @@ mod datalink {
+ 
+             assert!(!self.is_empty());
+ 
+-            let a = data[nlen] as u8;
+-            let b = data[nlen + 1] as u8;
+-            let c = data[nlen + 2] as u8;
+-            let d = data[nlen + 3] as u8;
+-            let e = data[nlen + 4] as u8;
+-            let f = data[nlen + 5] as u8;
+-
+-            [a, b, c, d, e, f]
++            [
++                data[nlen] as u8,
++                data[nlen + 1] as u8,
++                data[nlen + 2] as u8,
++                data[nlen + 3] as u8,
++                data[nlen + 4] as u8,
++                data[nlen + 5] as u8,
++            ]
+         }
+     }
+ 
+@@ -1144,9 +1207,9 @@ mod datalink {
+     }
+ }
+ 
+-#[cfg(target_os = "linux")]
++#[cfg(any(target_os = "android", target_os = "linux"))]
+ pub mod vsock {
+-    use ::sys::socket::addr::AddressFamily;
++    use crate::sys::socket::addr::AddressFamily;
+     use libc::{sa_family_t, sockaddr_vm};
+     use std::{fmt, mem};
+     use std::hash::{Hash, Hasher};
+@@ -1269,7 +1332,7 @@ mod tests {
+         let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap();
+ 
+         let sun_path1 = addr.sun_path();
+-        let sun_path2 = [0u8, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
++        let sun_path2 = [0u8, 110, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116];
+         assert_eq!(sun_path1.len(), sun_path2.len());
+         for i in 0..sun_path1.len() {
+             assert_eq!(sun_path1[i], sun_path2[i]);
+diff --git a/third_party/rust/nix/src/sys/socket/mod.rs b/third_party/rust/nix/src/sys/socket/mod.rs
+index 1c12c5f851734..631d281ed16af 100644
+--- a/third_party/rust/nix/src/sys/socket/mod.rs
++++ b/third_party/rust/nix/src/sys/socket/mod.rs
+@@ -1,14 +1,15 @@
+ //! Socket interface functions
+ //!
+ //! [Further reading](http://man7.org/linux/man-pages/man7/socket.7.html)
+-use {Error, Result};
+-use errno::Errno;
++use cfg_if::cfg_if;
++use crate::{Error, Result, errno::Errno};
+ use libc::{self, c_void, c_int, iovec, socklen_t, size_t,
+         CMSG_FIRSTHDR, CMSG_NXTHDR, CMSG_DATA, CMSG_LEN};
++use memoffset::offset_of;
+ use std::{mem, ptr, slice};
+ use std::os::unix::io::RawFd;
+-use sys::time::TimeVal;
+-use sys::uio::IoVec;
++use crate::sys::time::TimeVal;
++use crate::sys::uio::IoVec;
+ 
+ mod addr;
+ pub mod sockopt;
+@@ -30,11 +31,11 @@ pub use self::addr::{
+     LinkAddr,
+ };
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+-pub use ::sys::socket::addr::netlink::NetlinkAddr;
++pub use crate::sys::socket::addr::netlink::NetlinkAddr;
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+-pub use sys::socket::addr::alg::AlgAddr;
+-#[cfg(target_os = "linux")]
+-pub use sys::socket::addr::vsock::VsockAddr;
++pub use crate::sys::socket::addr::alg::AlgAddr;
++#[cfg(any(target_os = "android", target_os = "linux"))]
++pub use crate::sys::socket::addr::vsock::VsockAddr;
+ 
+ pub use libc::{
+     cmsghdr,
+@@ -92,6 +93,64 @@ pub enum SockProtocol {
+     /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html))
+     #[cfg(any(target_os = "ios", target_os = "macos"))]
+     KextControl = libc::SYSPROTO_CONTROL,
++    /// Receives routing and link updates and may be used to modify the routing tables (both IPv4 and IPv6), IP addresses, link
++    // parameters, neighbor setups, queueing disciplines, traffic classes and packet classifiers
++    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    NetlinkRoute = libc::NETLINK_ROUTE,
++    /// Reserved for user-mode socket protocols
++    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    NetlinkUserSock = libc::NETLINK_USERSOCK,
++    /// Query information about sockets of various protocol families from the kernel
++    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    NetlinkSockDiag = libc::NETLINK_SOCK_DIAG,
++    /// SELinux event notifications.
++    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    NetlinkSELinux = libc::NETLINK_SELINUX,
++    /// Open-iSCSI
++    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    NetlinkISCSI = libc::NETLINK_ISCSI,
++    /// Auditing
++    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    NetlinkAudit = libc::NETLINK_AUDIT,
++    /// Access to FIB lookup from user space
++    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    NetlinkFIBLookup = libc::NETLINK_FIB_LOOKUP,
++    /// Netfilter subsystem
++    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    NetlinkNetFilter = libc::NETLINK_NETFILTER,
++    /// SCSI Transports
++    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    NetlinkSCSITransport = libc::NETLINK_SCSITRANSPORT,
++    /// Infiniband RDMA
++    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    NetlinkRDMA = libc::NETLINK_RDMA,
++    /// Transport IPv6 packets from netfilter to user space.  Used by ip6_queue kernel module.
++    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    NetlinkIPv6Firewall = libc::NETLINK_IP6_FW,
++    /// DECnet routing messages
++    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    NetlinkDECNetRoutingMessage = libc::NETLINK_DNRTMSG,
++    /// Kernel messages to user space
++    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    NetlinkKObjectUEvent = libc::NETLINK_KOBJECT_UEVENT,
++    /// Netlink interface to request information about ciphers registered with the kernel crypto API as well as allow
++    /// configuration of the kernel crypto API.
++    /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html))
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    NetlinkCrypto = libc::NETLINK_CRYPTO,
+ }
+ 
+ libc_bitflags!{
+@@ -189,12 +248,22 @@ cfg_if! {
+     if #[cfg(any(target_os = "android", target_os = "linux"))] {
+         /// Unix credentials of the sending process.
+         ///
+-        /// This struct is used with the `SO_PEERCRED` ancillary message for UNIX sockets.
+-        #[repr(C)]
++        /// This struct is used with the `SO_PEERCRED` ancillary message
++        /// and the `SCM_CREDENTIALS` control message for UNIX sockets.
++        #[repr(transparent)]
+         #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+         pub struct UnixCredentials(libc::ucred);
+ 
+         impl UnixCredentials {
++            /// Creates a new instance with the credentials of the current process
++            pub fn new() -> Self {
++                UnixCredentials(libc::ucred {
++                    pid: crate::unistd::getpid().as_raw(),
++                    uid: crate::unistd::getuid().as_raw(),
++                    gid: crate::unistd::getgid().as_raw(),
++                })
++            }
++
+             /// Returns the process identifier
+             pub fn pid(&self) -> libc::pid_t {
+                 self.0.pid
+@@ -211,6 +280,12 @@ cfg_if! {
+             }
+         }
+ 
++        impl Default for UnixCredentials {
++            fn default() -> Self {
++                Self::new()
++            }
++        }
++
+         impl From<libc::ucred> for UnixCredentials {
+             fn from(cred: libc::ucred) -> Self {
+                 UnixCredentials(cred)
+@@ -222,13 +297,53 @@ cfg_if! {
+                 self.0
+             }
+         }
++    } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] {
++        /// Unix credentials of the sending process.
++        ///
++        /// This struct is used with the `SCM_CREDS` ancillary message for UNIX sockets.
++        #[repr(transparent)]
++        #[derive(Clone, Copy, Debug, Eq, PartialEq)]
++        pub struct UnixCredentials(libc::cmsgcred);
++
++        impl UnixCredentials {
++            /// Returns the process identifier
++            pub fn pid(&self) -> libc::pid_t {
++                self.0.cmcred_pid
++            }
++
++            /// Returns the real user identifier
++            pub fn uid(&self) -> libc::uid_t {
++                self.0.cmcred_uid
++            }
++
++            /// Returns the effective user identifier
++            pub fn euid(&self) -> libc::uid_t {
++                self.0.cmcred_euid
++            }
++
++            /// Returns the real group identifier
++            pub fn gid(&self) -> libc::gid_t {
++                self.0.cmcred_gid
++            }
++
++            /// Returns a list group identifiers (the first one being the effective GID)
++            pub fn groups(&self) -> &[libc::gid_t] {
++                unsafe { slice::from_raw_parts(self.0.cmcred_groups.as_ptr() as *const libc::gid_t, self.0.cmcred_ngroups as _) }
++            }
++        }
++
++        impl From<libc::cmsgcred> for UnixCredentials {
++            fn from(cred: libc::cmsgcred) -> Self {
++                UnixCredentials(cred)
++            }
++        }
+     }
+ }
+ 
+ /// Request for multicast socket operations
+ ///
+ /// This is a wrapper type around `ip_mreq`.
+-#[repr(C)]
++#[repr(transparent)]
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+ pub struct IpMembershipRequest(libc::ip_mreq);
+ 
+@@ -247,7 +362,7 @@ impl IpMembershipRequest {
+ /// Request for ipv6 multicast socket operations
+ ///
+ /// This is a wrapper type around `ipv6_mreq`.
+-#[repr(C)]
++#[repr(transparent)]
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+ pub struct Ipv6MembershipRequest(libc::ipv6_mreq);
+ 
+@@ -261,21 +376,6 @@ impl Ipv6MembershipRequest {
+     }
+ }
+ 
+-cfg_if! {
+-    // Darwin and DragonFly BSD always align struct cmsghdr to 32-bit only.
+-    if #[cfg(any(target_os = "dragonfly", target_os = "ios", target_os = "macos"))] {
+-        type align_of_cmsg_data = u32;
+-    } else {
+-        type align_of_cmsg_data = size_t;
+-    }
+-}
+-
+-/// A type that can be used to store ancillary data received by
+-/// [`recvmsg`](fn.recvmsg.html)
+-pub trait CmsgBuffer {
+-    fn as_bytes_mut(&mut self) -> &mut [u8];
+-}
+-
+ /// Create a buffer large enough for storing some control messages as returned
+ /// by [`recvmsg`](fn.recvmsg.html).
+ ///
+@@ -311,61 +411,11 @@ macro_rules! cmsg_space {
+                     CMSG_SPACE(mem::size_of::<$x>() as c_uint)
+                 } as usize;
+             )*
+-            let mut v = Vec::<u8>::with_capacity(space);
+-            // safe because any bit pattern is a valid u8
+-            unsafe {v.set_len(space)};
+-            v
++            Vec::<u8>::with_capacity(space)
+         }
+     }
+ }
+ 
+-/// A structure used to make room in a cmsghdr passed to recvmsg. The
+-/// size and alignment match that of a cmsghdr followed by a T, but the
+-/// fields are not accessible, as the actual types will change on a call
+-/// to recvmsg.
+-///
+-/// To make room for multiple messages, nest the type parameter with
+-/// tuples:
+-///
+-/// ```
+-/// use std::os::unix::io::RawFd;
+-/// use nix::sys::socket::CmsgSpace;
+-/// let cmsg: CmsgSpace<([RawFd; 3], CmsgSpace<[RawFd; 2]>)> = CmsgSpace::new();
+-/// ```
+-#[repr(C)]
+-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+-pub struct CmsgSpace<T> {
+-    _hdr: cmsghdr,
+-    _pad: [align_of_cmsg_data; 0],
+-    _data: T,
+-}
+-
+-impl<T> CmsgSpace<T> {
+-    /// Create a CmsgSpace<T>. The structure is used only for space, so
+-    /// the fields are uninitialized.
+-    #[deprecated( since="0.14.0", note="Use the cmsg_space! macro instead")]
+-    pub fn new() -> Self {
+-        // Safe because the fields themselves aren't accessible.
+-        unsafe { mem::uninitialized() }
+-    }
+-}
+-
+-impl<T> CmsgBuffer for CmsgSpace<T> {
+-    fn as_bytes_mut(&mut self) -> &mut [u8] {
+-        // Safe because nothing ever attempts to access CmsgSpace's fields
+-        unsafe {
+-            slice::from_raw_parts_mut(self as *mut CmsgSpace<T> as *mut u8,
+-                                      mem::size_of::<Self>())
+-        }
+-    }
+-}
+-
+-impl CmsgBuffer for Vec<u8> {
+-    fn as_bytes_mut(&mut self) -> &mut [u8] {
+-        &mut self[..]
+-    }
+-}
+-
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
+ pub struct RecvMsg<'a> {
+     pub bytes: usize,
+@@ -433,7 +483,11 @@ pub enum ControlMessageOwned {
+     /// Received version of
+     /// [`ControlMessage::ScmCredentials`][#enum.ControlMessage.html#variant.ScmCredentials]
+     #[cfg(any(target_os = "android", target_os = "linux"))]
+-    ScmCredentials(libc::ucred),
++    ScmCredentials(UnixCredentials),
++    /// Received version of
++    /// [`ControlMessage::ScmCreds`][#enum.ControlMessage.html#variant.ScmCreds]
++    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++    ScmCreds(UnixCredentials),
+     /// A message of type `SCM_TIMESTAMP`, containing the time the
+     /// packet was received by the kernel.
+     ///
+@@ -442,10 +496,6 @@ pub enum ControlMessageOwned {
+     ///
+     /// # Examples
+     ///
+-    // Disable this test on FreeBSD i386
+-    // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=222039
+-    #[cfg_attr(not(all(target_os = "freebsd", target_arch = "x86")), doc = " ```")]
+-    #[cfg_attr(all(target_os = "freebsd", target_arch = "x86"), doc = " ```no_run")]
+     /// # #[macro_use] extern crate nix;
+     /// # use nix::sys::socket::*;
+     /// # use nix::sys::uio::IoVec;
+@@ -528,6 +578,18 @@ pub enum ControlMessageOwned {
+         target_os = "openbsd",
+     ))]
+     Ipv4RecvDstAddr(libc::in_addr),
++
++    /// UDP Generic Receive Offload (GRO) allows receiving multiple UDP
++    /// packets from a single sender.
++    /// Fixed-size payloads are following one by one in a receive buffer.
++    /// This Control Message indicates the size of all smaller packets,
++    /// except, maybe, the last one.
++    ///
++    /// `UdpGroSegment` socket option should be enabled on a socket
++    /// to allow receiving GRO packets.
++    #[cfg(target_os = "linux")]
++    UdpGroSegments(u16),
++
+     /// Catch-all variant for unimplemented cmsg types.
+     #[doc(hidden)]
+     Unknown(UnknownCmsg),
+@@ -540,9 +602,9 @@ impl ControlMessageOwned {
+     /// specified in the header. Normally, the kernel ensures that this is the
+     /// case. "Correct" in this case includes correct length, alignment and
+     /// actual content.
+-    ///
+-    /// Returns `None` if the data may be unaligned.  In that case use
+-    /// `ControlMessageOwned::decode_from`.
++    // Clippy complains about the pointer alignment of `p`, not understanding
++    // that it's being fed to a function that can handle that.
++    #[allow(clippy::cast_ptr_alignment)]
+     unsafe fn decode_from(header: &cmsghdr) -> ControlMessageOwned
+     {
+         let p = CMSG_DATA(header);
+@@ -553,16 +615,20 @@ impl ControlMessageOwned {
+                 let n = len / mem::size_of::<RawFd>();
+                 let mut fds = Vec::with_capacity(n);
+                 for i in 0..n {
+-                    let fdp = (p as *const RawFd).offset(i as isize);
++                    let fdp = (p as *const RawFd).add(i);
+                     fds.push(ptr::read_unaligned(fdp));
+                 }
+-                let cmo = ControlMessageOwned::ScmRights(fds);
+-                cmo
++                ControlMessageOwned::ScmRights(fds)
+             },
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+             (libc::SOL_SOCKET, libc::SCM_CREDENTIALS) => {
+                 let cred: libc::ucred = ptr::read_unaligned(p as *const _);
+-                ControlMessageOwned::ScmCredentials(cred)
++                ControlMessageOwned::ScmCredentials(cred.into())
++            }
++            #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++            (libc::SOL_SOCKET, libc::SCM_CREDS) => {
++                let cred: libc::cmsgcred = ptr::read_unaligned(p as *const _);
++                ControlMessageOwned::ScmCreds(cred.into())
+             }
+             (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => {
+                 let tv: libc::timeval = ptr::read_unaligned(p as *const _);
+@@ -612,6 +678,11 @@ impl ControlMessageOwned {
+                 let dl = ptr::read_unaligned(p as *const libc::in_addr);
+                 ControlMessageOwned::Ipv4RecvDstAddr(dl)
+             },
++            #[cfg(target_os = "linux")]
++            (libc::SOL_UDP, libc::UDP_GRO) => {
++                let gso_size: u16 = ptr::read_unaligned(p as *const _);
++                ControlMessageOwned::UdpGroSegments(gso_size)
++            },
+             (_, _) => {
+                 let sl = slice::from_raw_parts(p, len);
+                 let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(&sl[..]));
+@@ -650,10 +721,22 @@ pub enum ControlMessage<'a> {
+     ///
+     /// For further information, please refer to the
+     /// [`unix(7)`](http://man7.org/linux/man-pages/man7/unix.7.html) man page.
+-    // FIXME: When `#[repr(transparent)]` is stable, use it on `UnixCredentials`
+-    // and put that in here instead of a raw ucred.
+     #[cfg(any(target_os = "android", target_os = "linux"))]
+-    ScmCredentials(&'a libc::ucred),
++    ScmCredentials(&'a UnixCredentials),
++    /// A message of type `SCM_CREDS`, containing the pid, uid, euid, gid and groups of
++    /// a process connected to the socket.
++    ///
++    /// This is similar to the socket options `LOCAL_CREDS` and `LOCAL_PEERCRED`, but
++    /// requires a process to explicitly send its credentials.
++    ///
++    /// Credentials are always overwritten by the kernel, so this variant does have
++    /// any data, unlike the receive-side
++    /// [`ControlMessageOwned::ScmCreds`][#enum.ControlMessageOwned.html#variant.ScmCreds].
++    ///
++    /// For further information, please refer to the
++    /// [`unix(4)`](https://www.freebsd.org/cgi/man.cgi?query=unix) man page.
++    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++    ScmCreds,
+ 
+     /// Set IV for `AF_ALG` crypto API.
+     ///
+@@ -685,6 +768,39 @@ pub enum ControlMessage<'a> {
+     ))]
+     AlgSetAeadAssoclen(&'a u32),
+ 
++    /// UDP GSO makes it possible for applications to generate network packets
++    /// for a virtual MTU much greater than the real one.
++    /// The length of the send data no longer matches the expected length on
++    /// the wire.
++    /// The size of the datagram payload as it should appear on the wire may be
++    /// passed through this control message.
++    /// Send buffer should consist of multiple fixed-size wire payloads
++    /// following one by one, and the last, possibly smaller one.
++    #[cfg(target_os = "linux")]
++    UdpGsoSegments(&'a u16),
++
++    /// Configure the sending addressing and interface for v4
++    ///
++    /// For further information, please refer to the
++    /// [`ip(7)`](http://man7.org/linux/man-pages/man7/ip.7.html) man page.
++    #[cfg(any(target_os = "linux",
++              target_os = "macos",
++              target_os = "netbsd",
++              target_os = "android",
++              target_os = "ios",))]
++    Ipv4PacketInfo(&'a libc::in_pktinfo),
++
++    /// Configure the sending addressing and interface for v6
++    ///
++    /// For further information, please refer to the
++    /// [`ipv6(7)`](http://man7.org/linux/man-pages/man7/ipv6.7.html) man page.
++    #[cfg(any(target_os = "linux",
++              target_os = "macos",
++              target_os = "netbsd",
++              target_os = "freebsd",
++              target_os = "android",
++              target_os = "ios",))]
++    Ipv6PacketInfo(&'a libc::in6_pktinfo),
+ }
+ 
+ // An opaque structure used to prevent cmsghdr from being a public type
+@@ -715,35 +831,66 @@ impl<'a> ControlMessage<'a> {
+ 
+     /// Return a reference to the payload data as a byte pointer
+     fn copy_to_cmsg_data(&self, cmsg_data: *mut u8) {
+-        let data_ptr = match self {
+-            &ControlMessage::ScmRights(fds) => {
++        let data_ptr = match *self {
++            ControlMessage::ScmRights(fds) => {
+                 fds as *const _ as *const u8
+             },
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            &ControlMessage::ScmCredentials(creds) => {
+-                creds as *const libc::ucred as *const u8
++            ControlMessage::ScmCredentials(creds) => {
++                &creds.0 as *const libc::ucred as *const u8
++            }
++            #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++            ControlMessage::ScmCreds => {
++                // The kernel overwrites the data, we just zero it
++                // to make sure it's not uninitialized memory
++                unsafe { ptr::write_bytes(cmsg_data, 0, self.len()) };
++                return
+             }
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            &ControlMessage::AlgSetIv(iv) => {
++            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_val(&af_alg_iv);
++
+                 unsafe {
+-                    let alg_iv = cmsg_data as *mut libc::af_alg_iv;
+-                    (*alg_iv).ivlen = iv.len() as u32;
++                    ptr::copy_nonoverlapping(
++                        &af_alg_iv as *const _ as *const u8,
++                        cmsg_data,
++                        size,
++                    );
+                     ptr::copy_nonoverlapping(
+                         iv.as_ptr(),
+-                        (*alg_iv).iv.as_mut_ptr(),
++                        cmsg_data.add(size),
+                         iv.len()
+                     );
+                 };
++
+                 return
+             },
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            &ControlMessage::AlgSetOp(op) => {
++            ControlMessage::AlgSetOp(op) => {
+                 op as *const _ as *const u8
+             },
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            &ControlMessage::AlgSetAeadAssoclen(len) => {
++            ControlMessage::AlgSetAeadAssoclen(len) => {
+                 len as *const _ as *const u8
+             },
++            #[cfg(target_os = "linux")]
++            ControlMessage::UdpGsoSegments(gso_size) => {
++                gso_size as *const _ as *const u8
++            },
++            #[cfg(any(target_os = "linux", target_os = "macos",
++                      target_os = "netbsd", target_os = "android",
++                      target_os = "ios",))]
++            ControlMessage::Ipv4PacketInfo(info) => info as *const _ as *const u8,
++            #[cfg(any(target_os = "linux", target_os = "macos",
++                      target_os = "netbsd", target_os = "freebsd",
++                      target_os = "android", target_os = "ios",))]
++            ControlMessage::Ipv6PacketInfo(info) => info as *const _ as *const u8,
+         };
+         unsafe {
+             ptr::copy_nonoverlapping(
+@@ -756,60 +903,101 @@ impl<'a> ControlMessage<'a> {
+ 
+     /// The size of the payload, excluding its cmsghdr
+     fn len(&self) -> usize {
+-        match self {
+-            &ControlMessage::ScmRights(fds) => {
++        match *self {
++            ControlMessage::ScmRights(fds) => {
+                 mem::size_of_val(fds)
+             },
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            &ControlMessage::ScmCredentials(creds) => {
++            ControlMessage::ScmCredentials(creds) => {
+                 mem::size_of_val(creds)
+             }
++            #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++            ControlMessage::ScmCreds => {
++                mem::size_of::<libc::cmsgcred>()
++            }
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            &ControlMessage::AlgSetIv(iv) => {
+-                mem::size_of::<libc::af_alg_iv>() + iv.len()
++            ControlMessage::AlgSetIv(iv) => {
++                mem::size_of_val(&iv) + iv.len()
+             },
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            &ControlMessage::AlgSetOp(op) => {
++            ControlMessage::AlgSetOp(op) => {
+                 mem::size_of_val(op)
+             },
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            &ControlMessage::AlgSetAeadAssoclen(len) => {
++            ControlMessage::AlgSetAeadAssoclen(len) => {
+                 mem::size_of_val(len)
+             },
++            #[cfg(target_os = "linux")]
++            ControlMessage::UdpGsoSegments(gso_size) => {
++                mem::size_of_val(gso_size)
++            },
++            #[cfg(any(target_os = "linux", target_os = "macos",
++              target_os = "netbsd", target_os = "android",
++              target_os = "ios",))]
++            ControlMessage::Ipv4PacketInfo(info) => mem::size_of_val(info),
++            #[cfg(any(target_os = "linux", target_os = "macos",
++              target_os = "netbsd", target_os = "freebsd",
++              target_os = "android", target_os = "ios",))]
++            ControlMessage::Ipv6PacketInfo(info) => mem::size_of_val(info),
+         }
+     }
+ 
+     /// Returns the value to put into the `cmsg_level` field of the header.
+     fn cmsg_level(&self) -> libc::c_int {
+-        match self {
+-            &ControlMessage::ScmRights(_) => libc::SOL_SOCKET,
++        match *self {
++            ControlMessage::ScmRights(_) => libc::SOL_SOCKET,
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            &ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET,
++            ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET,
++            #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++            ControlMessage::ScmCreds => libc::SOL_SOCKET,
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            &ControlMessage::AlgSetIv(_) | &ControlMessage::AlgSetOp(_) | &ControlMessage::AlgSetAeadAssoclen(_) => {
+-                libc::SOL_ALG
+-            },
++            ControlMessage::AlgSetIv(_) | ControlMessage::AlgSetOp(_) |
++                ControlMessage::AlgSetAeadAssoclen(_) => libc::SOL_ALG,
++            #[cfg(target_os = "linux")]
++            ControlMessage::UdpGsoSegments(_) => libc::SOL_UDP,
++            #[cfg(any(target_os = "linux", target_os = "macos",
++                      target_os = "netbsd", target_os = "android",
++                      target_os = "ios",))]
++            ControlMessage::Ipv4PacketInfo(_) => libc::IPPROTO_IP,
++            #[cfg(any(target_os = "linux", target_os = "macos",
++              target_os = "netbsd", target_os = "freebsd",
++              target_os = "android", target_os = "ios",))]
++            ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6,
+         }
+     }
+ 
+     /// Returns the value to put into the `cmsg_type` field of the header.
+     fn cmsg_type(&self) -> libc::c_int {
+-        match self {
+-            &ControlMessage::ScmRights(_) => libc::SCM_RIGHTS,
++        match *self {
++            ControlMessage::ScmRights(_) => libc::SCM_RIGHTS,
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            &ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS,
++            ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS,
++            #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++            ControlMessage::ScmCreds => libc::SCM_CREDS,
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            &ControlMessage::AlgSetIv(_) => {
++            ControlMessage::AlgSetIv(_) => {
+                 libc::ALG_SET_IV
+             },
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            &ControlMessage::AlgSetOp(_) => {
++            ControlMessage::AlgSetOp(_) => {
+                 libc::ALG_SET_OP
+             },
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            &ControlMessage::AlgSetAeadAssoclen(_) => {
++            ControlMessage::AlgSetAeadAssoclen(_) => {
+                 libc::ALG_SET_AEAD_ASSOCLEN
+             },
++            #[cfg(target_os = "linux")]
++            ControlMessage::UdpGsoSegments(_) => {
++                libc::UDP_SEGMENT
++            },
++            #[cfg(any(target_os = "linux", target_os = "macos",
++                      target_os = "netbsd", target_os = "android",
++                      target_os = "ios",))]
++            ControlMessage::Ipv4PacketInfo(_) => libc::IP_PKTINFO,
++            #[cfg(any(target_os = "linux", target_os = "macos",
++                      target_os = "netbsd", target_os = "freebsd",
++                      target_os = "android", target_os = "ios",))]
++            ControlMessage::Ipv6PacketInfo(_) => libc::IPV6_PKTINFO,
+         }
+     }
+ 
+@@ -836,12 +1024,303 @@ pub fn sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage],
+ 
+     // First size the buffer needed to hold the cmsgs.  It must be zeroed,
+     // because subsequent code will not clear the padding bytes.
+-    let cmsg_buffer = vec![0u8; capacity];
++    let mut cmsg_buffer = vec![0u8; capacity];
++
++    let mhdr = pack_mhdr_to_send(&mut cmsg_buffer[..], &iov, &cmsgs, addr);
++
++    let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) };
++
++    Errno::result(ret).map(|r| r as usize)
++}
++
++#[cfg(any(
++    target_os = "linux",
++    target_os = "android",
++    target_os = "freebsd",
++    target_os = "netbsd",
++))]
++#[derive(Debug)]
++pub struct SendMmsgData<'a, I, C>
++    where
++        I: AsRef<[IoVec<&'a [u8]>]>,
++        C: AsRef<[ControlMessage<'a>]>
++{
++    pub iov: I,
++    pub cmsgs: C,
++    pub addr: Option<SockAddr>,
++    pub _lt: std::marker::PhantomData<&'a I>,
++}
++
++/// An extension of `sendmsg` that allows the caller to transmit multiple
++/// messages on a socket using a single system call. This has performance
++/// benefits for some applications.
++///
++/// Allocations are performed for cmsgs and to build `msghdr` buffer
++///
++/// # Arguments
++///
++/// * `fd`:             Socket file descriptor
++/// * `data`:           Struct that implements `IntoIterator` with `SendMmsgData` items
++/// * `flags`:          Optional flags passed directly to the operating system.
++///
++/// # Returns
++/// `Vec` with numbers of sent bytes on each sent message.
++///
++/// # References
++/// [`sendmsg`](fn.sendmsg.html)
++#[cfg(any(
++    target_os = "linux",
++    target_os = "android",
++    target_os = "freebsd",
++    target_os = "netbsd",
++))]
++pub fn sendmmsg<'a, I, C>(
++    fd: RawFd,
++    data: impl std::iter::IntoIterator<Item=&'a SendMmsgData<'a, I, C>>,
++    flags: MsgFlags
++) -> Result<Vec<usize>>
++    where
++        I: AsRef<[IoVec<&'a [u8]>]> + 'a,
++        C: AsRef<[ControlMessage<'a>]> + 'a,
++{
++    let iter = data.into_iter();
++
++    let size_hint = iter.size_hint();
++    let reserve_items = size_hint.1.unwrap_or(size_hint.0);
++
++    let mut output = Vec::<libc::mmsghdr>::with_capacity(reserve_items);
++
++    let mut cmsgs_buffer = vec![0u8; 0];
++
++    for d in iter {
++        let cmsgs_start = cmsgs_buffer.len();
++        let cmsgs_required_capacity: usize = d.cmsgs.as_ref().iter().map(|c| c.space()).sum();
++        let cmsgs_buffer_need_capacity = cmsgs_start + cmsgs_required_capacity;
++        cmsgs_buffer.resize(cmsgs_buffer_need_capacity, 0);
++
++        output.push(libc::mmsghdr {
++            msg_hdr: pack_mhdr_to_send(
++                &mut cmsgs_buffer[cmsgs_start..],
++                &d.iov,
++                &d.cmsgs,
++                d.addr.as_ref()
++            ),
++            msg_len: 0,
++        });
++    };
++
++    let ret = unsafe { libc::sendmmsg(fd, output.as_mut_ptr(), output.len() as _, flags.bits() as _) };
++
++    let sent_messages = Errno::result(ret)? as usize;
++    let mut sent_bytes = Vec::with_capacity(sent_messages);
++
++    for item in &output {
++        sent_bytes.push(item.msg_len as usize);
++    }
++
++    Ok(sent_bytes)
++}
++
++
++#[cfg(any(
++    target_os = "linux",
++    target_os = "android",
++    target_os = "freebsd",
++    target_os = "netbsd",
++))]
++#[derive(Debug)]
++pub struct RecvMmsgData<'a, I>
++    where
++        I: AsRef<[IoVec<&'a mut [u8]>]> + 'a,
++{
++    pub iov: I,
++    pub cmsg_buffer: Option<&'a mut Vec<u8>>,
++}
++
++/// An extension of `recvmsg` that allows the caller to receive multiple
++/// messages from a socket using a single system call. This has
++/// performance benefits for some applications.
++///
++/// `iov` and `cmsg_buffer` should be constructed similarly to `recvmsg`
++///
++/// Multiple allocations are performed
++///
++/// # Arguments
++///
++/// * `fd`:             Socket file descriptor
++/// * `data`:           Struct that implements `IntoIterator` with `RecvMmsgData` items
++/// * `flags`:          Optional flags passed directly to the operating system.
++///
++/// # RecvMmsgData
++///
++/// * `iov`:            Scatter-gather list of buffers to receive the message
++/// * `cmsg_buffer`:    Space to receive ancillary data.  Should be created by
++///                     [`cmsg_space!`](macro.cmsg_space.html)
++///
++/// # Returns
++/// A `Vec` with multiple `RecvMsg`, one per received message
++///
++/// # References
++/// - [`recvmsg`](fn.recvmsg.html)
++/// - [`RecvMsg`](struct.RecvMsg.html)
++#[cfg(any(
++    target_os = "linux",
++    target_os = "android",
++    target_os = "freebsd",
++    target_os = "netbsd",
++))]
++pub fn recvmmsg<'a, I>(
++    fd: RawFd,
++    data: impl std::iter::IntoIterator<Item=&'a mut RecvMmsgData<'a, I>,
++        IntoIter=impl ExactSizeIterator + Iterator<Item=&'a mut RecvMmsgData<'a, I>>>,
++    flags: MsgFlags,
++    timeout: Option<crate::sys::time::TimeSpec>
++) -> Result<Vec<RecvMsg<'a>>>
++    where
++        I: AsRef<[IoVec<&'a mut [u8]>]> + 'a,
++{
++    let iter = data.into_iter();
++
++    let num_messages = iter.len();
++
++    let mut output: Vec<libc::mmsghdr> = Vec::with_capacity(num_messages);
++
++    // Addresses should be pre-allocated.  pack_mhdr_to_receive will store them
++    // as raw pointers, so we may not move them.  Turn the vec into a boxed
++    // slice so we won't inadvertently reallocate the vec.
++    let mut addresses = vec![mem::MaybeUninit::uninit(); num_messages]
++        .into_boxed_slice();
++
++    let results: Vec<_> = iter.enumerate().map(|(i, d)| {
++        let (msg_controllen, mhdr) = unsafe {
++            pack_mhdr_to_receive(
++                d.iov.as_ref(),
++                &mut d.cmsg_buffer,
++                addresses[i].as_mut_ptr(),
++            )
++        };
++
++        output.push(
++            libc::mmsghdr {
++                msg_hdr: mhdr,
++                msg_len: 0,
++            }
++        );
++
++        (msg_controllen as usize, &mut d.cmsg_buffer)
++    }).collect();
++
++    let timeout = if let Some(mut t) = timeout {
++        t.as_mut() as *mut libc::timespec
++    } else {
++        ptr::null_mut()
++    };
++
++    let ret = unsafe { libc::recvmmsg(fd, output.as_mut_ptr(), output.len() as _, flags.bits() as _, timeout) };
++
++    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,
++                    mmsghdr.msg_len as isize,
++                    msg_controllen,
++                    address,
++                    cmsg_buffer
++                )
++            }
++        })
++        .collect())
++}
++
++unsafe fn read_mhdr<'a, 'b>(
++    mhdr: msghdr,
++    r: isize,
++    msg_controllen: usize,
++    address: sockaddr_storage,
++    cmsg_buffer: &'a mut Option<&'b mut Vec<u8>>
++) -> RecvMsg<'b> {
++    let cmsghdr = {
++        if mhdr.msg_controllen > 0 {
++            // got control message(s)
++            cmsg_buffer
++                .as_mut()
++                .unwrap()
++                .set_len(mhdr.msg_controllen as usize);
++            debug_assert!(!mhdr.msg_control.is_null());
++            debug_assert!(msg_controllen >= mhdr.msg_controllen as usize);
++            CMSG_FIRSTHDR(&mhdr as *const msghdr)
++        } else {
++            ptr::null()
++        }.as_ref()
++    };
++
++    let address = sockaddr_storage_to_addr(
++        &address ,
++         mhdr.msg_namelen as usize
++    ).ok();
++
++    RecvMsg {
++        bytes: r as usize,
++        cmsghdr,
++        address,
++        flags: MsgFlags::from_bits_truncate(mhdr.msg_flags),
++        mhdr,
++    }
++}
++
++unsafe fn pack_mhdr_to_receive<'a, I>(
++    iov: I,
++    cmsg_buffer: &mut Option<&mut Vec<u8>>,
++    address: *mut sockaddr_storage,
++) -> (usize, msghdr)
++    where
++        I: AsRef<[IoVec<&'a mut [u8]>]> + 'a,
++{
++    let (msg_control, msg_controllen) = cmsg_buffer.as_mut()
++        .map(|v| (v.as_mut_ptr(), v.capacity()))
++        .unwrap_or((ptr::null_mut(), 0));
++
++    let mhdr = {
++        // Musl's msghdr has private fields, so this is the only way to
++        // initialize it.
++        let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
++        let p = mhdr.as_mut_ptr();
++        (*p).msg_name = address as *mut c_void;
++        (*p).msg_namelen = mem::size_of::<sockaddr_storage>() as socklen_t;
++        (*p).msg_iov = iov.as_ref().as_ptr() as *mut iovec;
++        (*p).msg_iovlen = iov.as_ref().len() as _;
++        (*p).msg_control = msg_control as *mut c_void;
++        (*p).msg_controllen = msg_controllen as _;
++        (*p).msg_flags = 0;
++        mhdr.assume_init()
++    };
++
++    (msg_controllen, mhdr)
++}
++
++fn pack_mhdr_to_send<'a, I, C>(
++    cmsg_buffer: &mut [u8],
++    iov: I,
++    cmsgs: C,
++    addr: Option<&SockAddr>
++) -> msghdr
++    where
++        I: AsRef<[IoVec<&'a [u8]>]>,
++        C: AsRef<[ControlMessage<'a>]>
++{
++    let capacity = cmsg_buffer.len();
+ 
+     // Next encode the sending address, if provided
+     let (name, namelen) = match addr {
+         Some(addr) => {
+-            let (x, y) = unsafe { addr.as_ffi_pair() };
++            let (x, y) = addr.as_ffi_pair();
+             (x as *const _, y)
+         },
+         None => (ptr::null(), 0),
+@@ -854,97 +1333,68 @@ pub fn sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage],
+         ptr::null_mut()
+     };
+ 
+-    let mhdr = {
++    let mhdr = unsafe {
+         // Musl's msghdr has private fields, so this is the only way to
+         // initialize it.
+-        let mut mhdr: msghdr = unsafe{mem::uninitialized()};
+-        mhdr.msg_name = name as *mut _;
+-        mhdr.msg_namelen = namelen;
++        let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
++        let p = mhdr.as_mut_ptr();
++        (*p).msg_name = name as *mut _;
++        (*p).msg_namelen = namelen;
+         // transmute iov into a mutable pointer.  sendmsg doesn't really mutate
+         // the buffer, but the standard says that it takes a mutable pointer
+-        mhdr.msg_iov = iov.as_ptr() as *mut _;
+-        mhdr.msg_iovlen = iov.len() as _;
+-        mhdr.msg_control = cmsg_ptr;
+-        mhdr.msg_controllen = capacity as _;
+-        mhdr.msg_flags = 0;
+-        mhdr
++        (*p).msg_iov = iov.as_ref().as_ptr() as *mut _;
++        (*p).msg_iovlen = iov.as_ref().len() as _;
++        (*p).msg_control = cmsg_ptr;
++        (*p).msg_controllen = capacity as _;
++        (*p).msg_flags = 0;
++        mhdr.assume_init()
+     };
+ 
+     // Encode each cmsg.  This must happen after initializing the header because
+     // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields.
+     // CMSG_FIRSTHDR is always safe
+-    let mut pmhdr: *mut cmsghdr = unsafe{CMSG_FIRSTHDR(&mhdr as *const msghdr)};
+-    for cmsg in cmsgs {
++    let mut pmhdr: *mut cmsghdr = unsafe { CMSG_FIRSTHDR(&mhdr as *const msghdr) };
++    for cmsg in cmsgs.as_ref() {
+         assert_ne!(pmhdr, ptr::null_mut());
+         // Safe because we know that pmhdr is valid, and we initialized it with
+         // sufficient space
+         unsafe { cmsg.encode_into(pmhdr) };
+         // Safe because mhdr is valid
+-        pmhdr = unsafe{CMSG_NXTHDR(&mhdr as *const msghdr, pmhdr)};
++        pmhdr = unsafe { CMSG_NXTHDR(&mhdr as *const msghdr, pmhdr) };
+     }
+ 
+-    let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) };
+-
+-    Errno::result(ret).map(|r| r as usize)
++    mhdr
+ }
+ 
+ /// Receive message in scatter-gather vectors from a socket, and
+ /// optionally receive ancillary data into the provided buffer.
+ /// If no ancillary data is desired, use () as the type parameter.
+ ///
++/// # Arguments
++///
++/// * `fd`:             Socket file descriptor
++/// * `iov`:            Scatter-gather list of buffers to receive the message
++/// * `cmsg_buffer`:    Space to receive ancillary data.  Should be created by
++///                     [`cmsg_space!`](macro.cmsg_space.html)
++/// * `flags`:          Optional flags passed directly to the operating system.
++///
+ /// # References
+ /// [recvmsg(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html)
+ pub fn recvmsg<'a>(fd: RawFd, iov: &[IoVec<&mut [u8]>],
+-                   cmsg_buffer: Option<&'a mut dyn CmsgBuffer>,
++                   mut cmsg_buffer: Option<&'a mut Vec<u8>>,
+                    flags: MsgFlags) -> Result<RecvMsg<'a>>
+ {
+-    let mut address: sockaddr_storage = unsafe { mem::uninitialized() };
+-    let (msg_control, msg_controllen) = match cmsg_buffer {
+-        Some(cmsgspace) => {
+-            let msg_buf = cmsgspace.as_bytes_mut();
+-            (msg_buf.as_mut_ptr(), msg_buf.len())
+-        },
+-        None => (ptr::null_mut(), 0),
+-    };
+-    let mut mhdr = {
+-        // Musl's msghdr has private fields, so this is the only way to
+-        // initialize it.
+-        let mut mhdr: msghdr = unsafe{mem::uninitialized()};
+-        mhdr.msg_name = &mut address as *mut sockaddr_storage as *mut c_void;
+-        mhdr.msg_namelen = mem::size_of::<sockaddr_storage>() as socklen_t;
+-        mhdr.msg_iov = iov.as_ptr() as *mut iovec;
+-        mhdr.msg_iovlen = iov.len() as _;
+-        mhdr.msg_control = msg_control as *mut c_void;
+-        mhdr.msg_controllen = msg_controllen as _;
+-        mhdr.msg_flags = 0;
+-        mhdr
++    let mut address = mem::MaybeUninit::uninit();
++
++    let (msg_controllen, mut mhdr) = unsafe {
++        pack_mhdr_to_receive(&iov, &mut cmsg_buffer, address.as_mut_ptr())
+     };
+ 
+     let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) };
+ 
+-    Errno::result(ret).map(|r| {
+-        let cmsghdr = unsafe {
+-            if mhdr.msg_controllen > 0 {
+-                // got control message(s)
+-                debug_assert!(!mhdr.msg_control.is_null());
+-                debug_assert!(msg_controllen >= mhdr.msg_controllen as usize);
+-                CMSG_FIRSTHDR(&mhdr as *const msghdr)
+-            } else {
+-                ptr::null()
+-            }.as_ref()
+-        };
++    let r = Errno::result(ret)?;
+ 
+-        let address = unsafe {
+-            sockaddr_storage_to_addr(&address, mhdr.msg_namelen as usize).ok()
+-        };
+-        RecvMsg {
+-            bytes: r as usize,
+-            cmsghdr,
+-            address,
+-            flags: MsgFlags::from_bits_truncate(mhdr.msg_flags),
+-            mhdr,
+-        }
+-    })
++    Ok(unsafe { read_mhdr(mhdr, r, msg_controllen, address.assume_init(), &mut cmsg_buffer) })
+ }
+ 
+ 
+@@ -1071,12 +1521,15 @@ pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> {
+ }
+ 
+ /// Receive data from a connectionless or connection-oriented socket. Returns
+-/// the number of bytes read and the socket address of the sender.
++/// the number of bytes read and, for connectionless sockets,  the socket
++/// address of the sender.
+ ///
+ /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html)
+-pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) -> Result<(usize, SockAddr)> {
++pub fn recvfrom(sockfd: RawFd, buf: &mut [u8])
++    -> Result<(usize, Option<SockAddr>)>
++{
+     unsafe {
+-        let addr: sockaddr_storage = mem::zeroed();
++        let mut addr: sockaddr_storage = mem::zeroed();
+         let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
+ 
+         let ret = Errno::result(libc::recvfrom(
+@@ -1084,11 +1537,14 @@ pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) -> Result<(usize, SockAddr)> {
+             buf.as_ptr() as *mut c_void,
+             buf.len() as size_t,
+             0,
+-            mem::transmute(&addr),
+-            &mut len as *mut socklen_t))?;
++            &mut addr as *mut libc::sockaddr_storage as *mut libc::sockaddr,
++            &mut len as *mut socklen_t))? as usize;
+ 
+-        sockaddr_storage_to_addr(&addr, len as usize)
+-            .map(|addr| (ret as usize, addr))
++        match sockaddr_storage_to_addr(&addr, len as usize) {
++            Err(Error::Sys(Errno::ENOTCONN)) => Ok((ret, None)),
++            Ok(addr) => Ok((ret, Some(addr))),
++            Err(e) => Err(e)
++        }
+     }
+ }
+ 
+@@ -1121,24 +1577,6 @@ pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize> {
+  *
+  */
+ 
+-/// 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 {
+@@ -1190,14 +1628,18 @@ pub fn setsockopt<O: SetSockOpt>(fd: RawFd, opt: O, val: &O::Val) -> Result<()>
+ /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html)
+ pub fn getpeername(fd: RawFd) -> Result<SockAddr> {
+     unsafe {
+-        let addr: sockaddr_storage = mem::uninitialized();
++        let mut addr = mem::MaybeUninit::uninit();
+         let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
+ 
+-        let ret = libc::getpeername(fd, mem::transmute(&addr), &mut len);
++        let ret = libc::getpeername(
++            fd,
++            addr.as_mut_ptr() as *mut libc::sockaddr,
++            &mut len
++        );
+ 
+         Errno::result(ret)?;
+ 
+-        sockaddr_storage_to_addr(&addr, len as usize)
++        sockaddr_storage_to_addr(&addr.assume_init(), len as usize)
+     }
+ }
+ 
+@@ -1206,60 +1648,92 @@ pub fn getpeername(fd: RawFd) -> Result<SockAddr> {
+ /// [Further reading](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html)
+ pub fn getsockname(fd: RawFd) -> Result<SockAddr> {
+     unsafe {
+-        let addr: sockaddr_storage = mem::uninitialized();
++        let mut addr = mem::MaybeUninit::uninit();
+         let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
+ 
+-        let ret = libc::getsockname(fd, mem::transmute(&addr), &mut len);
++        let ret = libc::getsockname(
++            fd,
++            addr.as_mut_ptr() as *mut libc::sockaddr,
++            &mut len
++        );
+ 
+         Errno::result(ret)?;
+ 
+-        sockaddr_storage_to_addr(&addr, len as usize)
++        sockaddr_storage_to_addr(&addr.assume_init(), len as usize)
+     }
+ }
+ 
+-/// Return the appropriate `SockAddr` type from a `sockaddr_storage` of a certain
+-/// size.  In C this would usually be done by casting.  The `len` argument
++/// Return the appropriate `SockAddr` type from a `sockaddr_storage` of a
++/// certain size.
++///
++/// In C this would usually be done by casting.  The `len` argument
+ /// should be the number of bytes in the `sockaddr_storage` that are actually
+ /// allocated and valid.  It must be at least as large as all the useful parts
+ /// of the structure.  Note that in the case of a `sockaddr_un`, `len` need not
+ /// include the terminating null.
+-pub unsafe fn sockaddr_storage_to_addr(
++pub fn sockaddr_storage_to_addr(
+     addr: &sockaddr_storage,
+     len: usize) -> Result<SockAddr> {
+ 
++    assert!(len <= mem::size_of::<sockaddr_un>());
+     if len < mem::size_of_val(&addr.ss_family) {
+         return Err(Error::Sys(Errno::ENOTCONN));
+     }
+ 
+-    match addr.ss_family as c_int {
++    match c_int::from(addr.ss_family) {
+         libc::AF_INET => {
+-            assert!(len as usize == mem::size_of::<sockaddr_in>());
+-            let ret = *(addr as *const _ as *const sockaddr_in);
+-            Ok(SockAddr::Inet(InetAddr::V4(ret)))
++            assert_eq!(len as usize, mem::size_of::<sockaddr_in>());
++            let sin = unsafe {
++                *(addr as *const sockaddr_storage as *const sockaddr_in)
++            };
++            Ok(SockAddr::Inet(InetAddr::V4(sin)))
+         }
+         libc::AF_INET6 => {
+-            assert!(len as usize == mem::size_of::<sockaddr_in6>());
+-            Ok(SockAddr::Inet(InetAddr::V6(*(addr as *const _ as *const sockaddr_in6))))
++            assert_eq!(len as usize, mem::size_of::<sockaddr_in6>());
++            let sin6 = unsafe {
++                *(addr as *const _ as *const sockaddr_in6)
++            };
++            Ok(SockAddr::Inet(InetAddr::V6(sin6)))
+         }
+         libc::AF_UNIX => {
+-            let sun = *(addr as *const _ as *const sockaddr_un);
+             let pathlen = len - offset_of!(sockaddr_un, sun_path);
++            let sun = unsafe {
++                *(addr as *const _ as *const sockaddr_un)
++            };
+             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;
+-            Ok(SockAddr::Netlink(NetlinkAddr(*(addr as *const _ as *const sockaddr_nl))))
++            let snl = unsafe {
++                *(addr as *const _ as *const sockaddr_nl)
++            };
++            Ok(SockAddr::Netlink(NetlinkAddr(snl)))
+         }
+         #[cfg(any(target_os = "android", target_os = "linux"))]
+         libc::AF_ALG => {
+             use libc::sockaddr_alg;
+-            Ok(SockAddr::Alg(AlgAddr(*(addr as *const _ as *const sockaddr_alg))))
++            let salg = unsafe {
++                *(addr as *const _ as *const sockaddr_alg)
++            };
++            Ok(SockAddr::Alg(AlgAddr(salg)))
+         }
+-        #[cfg(target_os = "linux")]
++        #[cfg(any(target_os = "android", target_os = "linux"))]
+         libc::AF_VSOCK => {
+             use libc::sockaddr_vm;
+-            Ok(SockAddr::Vsock(VsockAddr(*(addr as *const _ as *const sockaddr_vm))))
++            let svm = unsafe {
++                *(addr as *const _ as *const sockaddr_vm)
++            };
++            Ok(SockAddr::Vsock(VsockAddr(svm)))
+         }
+         af => panic!("unexpected address family {}", af),
+     }
+diff --git a/third_party/rust/nix/src/sys/socket/sockopt.rs b/third_party/rust/nix/src/sys/socket/sockopt.rs
+index a996010018d5b..5b7b4feafb49a 100644
+--- a/third_party/rust/nix/src/sys/socket/sockopt.rs
++++ b/third_party/rust/nix/src/sys/socket/sockopt.rs
+@@ -1,9 +1,13 @@
++use cfg_if::cfg_if;
+ use super::{GetSockOpt, SetSockOpt};
+-use Result;
+-use errno::Errno;
+-use sys::time::TimeVal;
++use crate::Result;
++use crate::errno::Errno;
++use crate::sys::time::TimeVal;
+ use libc::{self, c_int, c_void, socklen_t};
+-use std::mem;
++use std::mem::{
++    self,
++    MaybeUninit
++};
+ use std::os::unix::io::RawFd;
+ use std::ffi::{OsStr, OsString};
+ #[cfg(target_family = "unix")]
+@@ -84,14 +88,14 @@ macro_rules! getsockopt_impl {
+ 
+             fn get(&self, fd: RawFd) -> Result<$ty> {
+                 unsafe {
+-                    let mut getter: $getter = Get::blank();
++                    let mut getter: $getter = Get::uninit();
+ 
+                     let res = libc::getsockopt(fd, $level, $flag,
+                                                getter.ffi_ptr(),
+                                                getter.ffi_len());
+                     Errno::result(res)?;
+ 
+-                    Ok(getter.unwrap())
++                    Ok(getter.assume_init())
+                 }
+             }
+         }
+@@ -248,6 +252,10 @@ sockopt_impl!(Both, TcpKeepAlive, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, u32);
+           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);
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+@@ -257,6 +265,8 @@ sockopt_impl!(SetOnly, SndBufForce, libc::SOL_SOCKET, libc::SO_SNDBUFFORCE, usiz
+ sockopt_impl!(GetOnly, SockType, libc::SOL_SOCKET, libc::SO_TYPE, super::SockType);
+ sockopt_impl!(GetOnly, AcceptConn, libc::SOL_SOCKET, libc::SO_ACCEPTCONN, bool);
+ #[cfg(any(target_os = "android", target_os = "linux"))]
++sockopt_impl!(Both, BindToDevice, libc::SOL_SOCKET, libc::SO_BINDTODEVICE, OsString<[u8; libc::IFNAMSIZ]>);
++#[cfg(any(target_os = "android", target_os = "linux"))]
+ sockopt_impl!(GetOnly, OriginalDst, libc::SOL_IP, libc::SO_ORIGINAL_DST, libc::sockaddr_in);
+ sockopt_impl!(Both, ReceiveTimestamp, libc::SOL_SOCKET, libc::SO_TIMESTAMP, bool);
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+@@ -305,7 +315,10 @@ sockopt_impl!(Both, Ipv4RecvIf, libc::IPPROTO_IP, libc::IP_RECVIF, bool);
+     target_os = "openbsd",
+ ))]
+ sockopt_impl!(Both, Ipv4RecvDstAddr, libc::IPPROTO_IP, libc::IP_RECVDSTADDR, bool);
+-
++#[cfg(target_os = "linux")]
++sockopt_impl!(Both, UdpGsoSegment, libc::SOL_UDP, libc::UDP_SEGMENT, libc::c_int);
++#[cfg(target_os = "linux")]
++sockopt_impl!(Both, UdpGroSegment, libc::IPPROTO_UDP, libc::UDP_GRO, bool);
+ 
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[derive(Copy, Clone, Debug)]
+@@ -364,16 +377,16 @@ impl<T> SetSockOpt for AlgSetKey<T> where T: AsRef<[u8]> + Clone {
+ 
+ /// Helper trait that describes what is expected from a `GetSockOpt` getter.
+ unsafe trait Get<T> {
+-    /// Returns an empty value.
+-    unsafe fn blank() -> Self;
++    /// Returns an uninitialized value.
++    unsafe fn uninit() -> Self;
+     /// Returns a pointer to the stored value. This pointer will be passed to the system's
+     /// `getsockopt` call (`man 3p getsockopt`, argument `option_value`).
+     fn ffi_ptr(&mut self) -> *mut c_void;
+     /// Returns length of the stored value. This pointer will be passed to the system's
+     /// `getsockopt` call (`man 3p getsockopt`, argument `option_len`).
+     fn ffi_len(&mut self) -> *mut socklen_t;
+-    /// Returns the stored value.
+-    unsafe fn unwrap(self) -> T;
++    /// Returns the hopefully initialized inner value.
++    unsafe fn assume_init(self) -> T;
+ }
+ 
+ /// Helper trait that describes what is expected from a `SetSockOpt` setter.
+@@ -391,28 +404,28 @@ unsafe trait Set<'a, T> {
+ /// Getter for an arbitrary `struct`.
+ struct GetStruct<T> {
+     len: socklen_t,
+-    val: T,
++    val: MaybeUninit<T>,
+ }
+ 
+ unsafe impl<T> Get<T> for GetStruct<T> {
+-    unsafe fn blank() -> Self {
++    unsafe fn uninit() -> Self {
+         GetStruct {
+             len: mem::size_of::<T>() as socklen_t,
+-            val: mem::zeroed(),
++            val: MaybeUninit::uninit(),
+         }
+     }
+ 
+     fn ffi_ptr(&mut self) -> *mut c_void {
+-        &mut self.val as *mut T as *mut c_void
++        self.val.as_mut_ptr() as *mut c_void
+     }
+ 
+     fn ffi_len(&mut self) -> *mut socklen_t {
+         &mut self.len
+     }
+ 
+-    unsafe fn unwrap(self) -> T {
+-        assert!(self.len as usize == mem::size_of::<T>(), "invalid getsockopt implementation");
+-        self.val
++    unsafe fn assume_init(self) -> T {
++        assert_eq!(self.len as usize, mem::size_of::<T>(), "invalid getsockopt implementation");
++        self.val.assume_init()
+     }
+ }
+ 
+@@ -423,7 +436,7 @@ struct SetStruct<'a, T: 'static> {
+ 
+ unsafe impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
+     fn new(ptr: &'a T) -> SetStruct<'a, T> {
+-        SetStruct { ptr: ptr }
++        SetStruct { ptr }
+     }
+ 
+     fn ffi_ptr(&self) -> *const c_void {
+@@ -438,28 +451,28 @@ unsafe impl<'a, T> Set<'a, T> for SetStruct<'a, T> {
+ /// Getter for a boolean value.
+ struct GetBool {
+     len: socklen_t,
+-    val: c_int,
++    val: MaybeUninit<c_int>,
+ }
+ 
+ unsafe impl Get<bool> for GetBool {
+-    unsafe fn blank() -> Self {
++    unsafe fn uninit() -> Self {
+         GetBool {
+             len: mem::size_of::<c_int>() as socklen_t,
+-            val: mem::zeroed(),
++            val: MaybeUninit::uninit(),
+         }
+     }
+ 
+     fn ffi_ptr(&mut self) -> *mut c_void {
+-        &mut self.val as *mut c_int as *mut c_void
++        self.val.as_mut_ptr() as *mut c_void
+     }
+ 
+     fn ffi_len(&mut self) -> *mut socklen_t {
+         &mut self.len
+     }
+ 
+-    unsafe fn unwrap(self) -> bool {
+-        assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation");
+-        self.val != 0
++    unsafe fn assume_init(self) -> bool {
++        assert_eq!(self.len as usize, mem::size_of::<c_int>(), "invalid getsockopt implementation");
++        self.val.assume_init() != 0
+     }
+ }
+ 
+@@ -485,28 +498,28 @@ unsafe impl<'a> Set<'a, bool> for SetBool {
+ /// Getter for an `u8` value.
+ struct GetU8 {
+     len: socklen_t,
+-    val: u8,
++    val: MaybeUninit<u8>,
+ }
+ 
+ unsafe impl Get<u8> for GetU8 {
+-    unsafe fn blank() -> Self {
++    unsafe fn uninit() -> Self {
+         GetU8 {
+             len: mem::size_of::<u8>() as socklen_t,
+-            val: mem::zeroed(),
++            val: MaybeUninit::uninit(),
+         }
+     }
+ 
+     fn ffi_ptr(&mut self) -> *mut c_void {
+-        &mut self.val as *mut u8 as *mut c_void
++        self.val.as_mut_ptr() as *mut c_void
+     }
+ 
+     fn ffi_len(&mut self) -> *mut socklen_t {
+         &mut self.len
+     }
+ 
+-    unsafe fn unwrap(self) -> u8 {
+-        assert!(self.len as usize == mem::size_of::<u8>(), "invalid getsockopt implementation");
+-        self.val as u8
++    unsafe fn assume_init(self) -> u8 {
++        assert_eq!(self.len as usize, mem::size_of::<u8>(), "invalid getsockopt implementation");
++        self.val.assume_init()
+     }
+ }
+ 
+@@ -532,28 +545,28 @@ unsafe impl<'a> Set<'a, u8> for SetU8 {
+ /// Getter for an `usize` value.
+ struct GetUsize {
+     len: socklen_t,
+-    val: c_int,
++    val: MaybeUninit<c_int>,
+ }
+ 
+ unsafe impl Get<usize> for GetUsize {
+-    unsafe fn blank() -> Self {
++    unsafe fn uninit() -> Self {
+         GetUsize {
+             len: mem::size_of::<c_int>() as socklen_t,
+-            val: mem::zeroed(),
++            val: MaybeUninit::uninit(),
+         }
+     }
+ 
+     fn ffi_ptr(&mut self) -> *mut c_void {
+-        &mut self.val as *mut c_int as *mut c_void
++        self.val.as_mut_ptr() as *mut c_void
+     }
+ 
+     fn ffi_len(&mut self) -> *mut socklen_t {
+         &mut self.len
+     }
+ 
+-    unsafe fn unwrap(self) -> usize {
+-        assert!(self.len as usize == mem::size_of::<c_int>(), "invalid getsockopt implementation");
+-        self.val as usize
++    unsafe fn assume_init(self) -> usize {
++        assert_eq!(self.len as usize, mem::size_of::<c_int>(), "invalid getsockopt implementation");
++        self.val.assume_init() as usize
+     }
+ }
+ 
+@@ -579,27 +592,29 @@ unsafe impl<'a> Set<'a, usize> for SetUsize {
+ /// Getter for a `OsString` value.
+ struct GetOsString<T: AsMut<[u8]>> {
+     len: socklen_t,
+-    val: T,
++    val: MaybeUninit<T>,
+ }
+ 
+ unsafe impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
+-    unsafe fn blank() -> Self {
++    unsafe fn uninit() -> Self {
+         GetOsString {
+             len: mem::size_of::<T>() as socklen_t,
+-            val: mem::zeroed(),
++            val: MaybeUninit::uninit(),
+         }
+     }
+ 
+     fn ffi_ptr(&mut self) -> *mut c_void {
+-        &mut self.val as *mut T as *mut c_void
++        self.val.as_mut_ptr() as *mut c_void
+     }
+ 
+     fn ffi_len(&mut self) -> *mut socklen_t {
+         &mut self.len
+     }
+ 
+-    unsafe fn unwrap(mut self) -> OsString {
+-        OsStr::from_bytes(self.val.as_mut()).to_owned()
++    unsafe fn assume_init(self) -> OsString {
++        let len = self.len as usize;
++        let mut v = self.val.assume_init();
++        OsStr::from_bytes(&v.as_mut()[0..len]).to_owned()
+     }
+ }
+ 
+@@ -640,11 +655,11 @@ mod test {
+     #[test]
+     fn is_socket_type_unix() {
+         use super::super::*;
+-        use ::unistd::close;
++        use crate::unistd::close;
+ 
+         let (a, b) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty()).unwrap();
+         let a_type = getsockopt(a, super::SockType).unwrap();
+-        assert!(a_type == SockType::Stream);
++        assert_eq!(a_type, SockType::Stream);
+         close(a).unwrap();
+         close(b).unwrap();
+     }
+@@ -652,11 +667,11 @@ mod test {
+     #[test]
+     fn is_socket_type_dgram() {
+         use super::super::*;
+-        use ::unistd::close;
++        use crate::unistd::close;
+ 
+         let s = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), None).unwrap();
+         let s_type = getsockopt(s, super::SockType).unwrap();
+-        assert!(s_type == SockType::Datagram);
++        assert_eq!(s_type, SockType::Datagram);
+         close(s).unwrap();
+     }
+ 
+@@ -666,7 +681,7 @@ mod test {
+     #[test]
+     fn can_get_listen_on_tcp_socket() {
+         use super::super::*;
+-        use ::unistd::close;
++        use crate::unistd::close;
+ 
+         let s = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
+         let s_listening = getsockopt(s, super::AcceptConn).unwrap();
+diff --git a/third_party/rust/nix/src/sys/stat.rs b/third_party/rust/nix/src/sys/stat.rs
+index 66c8c9dd1b720..df81a2cb329d6 100644
+--- a/third_party/rust/nix/src/sys/stat.rs
++++ b/third_party/rust/nix/src/sys/stat.rs
+@@ -1,13 +1,12 @@
+ pub use libc::{dev_t, mode_t};
+ pub use libc::stat as FileStat;
+ 
+-use {Result, NixPath};
+-use errno::Errno;
+-use fcntl::{AtFlags, at_rawfd};
+-use libc;
++use crate::{Result, NixPath, errno::Errno};
++#[cfg(not(target_os = "redox"))]
++use crate::fcntl::{AtFlags, at_rawfd};
+ use std::mem;
+ use std::os::unix::io::RawFd;
+-use sys::time::{TimeSpec, TimeVal};
++use crate::sys::time::{TimeSpec, TimeVal};
+ 
+ libc_bitflags!(
+     pub struct SFlag: mode_t {
+@@ -78,49 +77,50 @@ pub fn umask(mode: Mode) -> Mode {
+ }
+ 
+ pub fn stat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
+-    let mut dst = unsafe { mem::uninitialized() };
++    let mut dst = mem::MaybeUninit::uninit();
+     let res = path.with_nix_path(|cstr| {
+         unsafe {
+-            libc::stat(cstr.as_ptr(), &mut dst as *mut FileStat)
++            libc::stat(cstr.as_ptr(), dst.as_mut_ptr())
+         }
+     })?;
+ 
+     Errno::result(res)?;
+ 
+-    Ok(dst)
++    Ok(unsafe{dst.assume_init()})
+ }
+ 
+ pub fn lstat<P: ?Sized + NixPath>(path: &P) -> Result<FileStat> {
+-    let mut dst = unsafe { mem::uninitialized() };
++    let mut dst = mem::MaybeUninit::uninit();
+     let res = path.with_nix_path(|cstr| {
+         unsafe {
+-            libc::lstat(cstr.as_ptr(), &mut dst as *mut FileStat)
++            libc::lstat(cstr.as_ptr(), dst.as_mut_ptr())
+         }
+     })?;
+ 
+     Errno::result(res)?;
+ 
+-    Ok(dst)
++    Ok(unsafe{dst.assume_init()})
+ }
+ 
+ pub fn fstat(fd: RawFd) -> Result<FileStat> {
+-    let mut dst = unsafe { mem::uninitialized() };
+-    let res = unsafe { libc::fstat(fd, &mut dst as *mut FileStat) };
++    let mut dst = mem::MaybeUninit::uninit();
++    let res = unsafe { libc::fstat(fd, dst.as_mut_ptr()) };
+ 
+     Errno::result(res)?;
+ 
+-    Ok(dst)
++    Ok(unsafe{dst.assume_init()})
+ }
+ 
++#[cfg(not(target_os = "redox"))]
+ pub fn fstatat<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, f: AtFlags) -> Result<FileStat> {
+-    let mut dst = unsafe { mem::uninitialized() };
++    let mut dst = mem::MaybeUninit::uninit();
+     let res = pathname.with_nix_path(|cstr| {
+-        unsafe { libc::fstatat(dirfd, cstr.as_ptr(), &mut dst as *mut FileStat, f.bits() as libc::c_int) }
++        unsafe { libc::fstatat(dirfd, cstr.as_ptr(), dst.as_mut_ptr(), f.bits() as libc::c_int) }
+     })?;
+ 
+     Errno::result(res)?;
+ 
+-    Ok(dst)
++    Ok(unsafe{dst.assume_init()})
+ }
+ 
+ /// Change the file permission bits of the file specified by a file descriptor.
+@@ -150,13 +150,14 @@ pub enum FchmodatFlags {
+ /// If `flag` is `FchmodatFlags::NoFollowSymlink` and `path` names a symbolic link,
+ /// then the mode of the symbolic link is changed.
+ ///
+-/// `fchmod(None, path, mode, FchmodatFlags::FollowSymlink)` is identical to
++/// `fchmodat(None, path, mode, FchmodatFlags::FollowSymlink)` is identical to
+ /// a call `libc::chmod(path, mode)`. That's why `chmod` is unimplemented
+ /// in the `nix` crate.
+ ///
+ /// # References
+ ///
+ /// [fchmodat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html).
++#[cfg(not(target_os = "redox"))]
+ pub fn fchmodat<P: ?Sized + NixPath>(
+     dirfd: Option<RawFd>,
+     path: &P,
+@@ -260,6 +261,7 @@ pub enum UtimensatFlags {
+ /// # References
+ ///
+ /// [utimensat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/utimens.html).
++#[cfg(not(target_os = "redox"))]
+ pub fn utimensat<P: ?Sized + NixPath>(
+     dirfd: Option<RawFd>,
+     path: &P,
+@@ -285,6 +287,7 @@ pub fn utimensat<P: ?Sized + NixPath>(
+     Errno::result(res).map(drop)
+ }
+ 
++#[cfg(not(target_os = "redox"))]
+ pub fn mkdirat<P: ?Sized + NixPath>(fd: RawFd, path: &P, mode: Mode) -> Result<()> {
+     let res = path.with_nix_path(|cstr| {
+         unsafe { libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) }
+diff --git a/third_party/rust/nix/src/sys/statfs.rs b/third_party/rust/nix/src/sys/statfs.rs
+index d4596bf336958..27b72592b9a30 100644
+--- a/third_party/rust/nix/src/sys/statfs.rs
++++ b/third_party/rust/nix/src/sys/statfs.rs
+@@ -4,10 +4,7 @@ use std::os::unix::io::AsRawFd;
+ #[cfg(not(any(target_os = "linux", target_os = "android")))]
+ use std::ffi::CStr;
+ 
+-use libc;
+-
+-use {NixPath, Result};
+-use errno::Errno;
++use crate::{NixPath, Result, errno::Errno};
+ 
+ #[cfg(target_os = "android")]
+ pub type fsid_t = libc::__fsid_t;
+@@ -15,81 +12,95 @@ pub type fsid_t = libc::__fsid_t;
+ pub type fsid_t = libc::fsid_t;
+ 
+ #[derive(Clone, Copy)]
++#[repr(transparent)]
+ pub struct Statfs(libc::statfs);
+ 
+ #[cfg(target_os = "freebsd")]
+-#[derive(Eq, Copy, Clone, PartialEq, Debug)]
+-pub struct FsType(u32);
++type fs_type_t = u32;
+ #[cfg(target_os = "android")]
+-#[derive(Eq, Copy, Clone, PartialEq, Debug)]
+-pub struct FsType(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(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(libc::c_ulong);
++type fs_type_t = libc::c_ulong;
+ #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
++type fs_type_t = libc::__fsword_t;
++
++#[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(libc::c_long);
+-
+-#[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 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);
++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
+     #[cfg(not(any(
+         target_os = "openbsd",
++        target_os = "dragonfly",
+         target_os = "ios",
+         target_os = "macos"
+     )))]
+@@ -105,32 +116,35 @@ impl Statfs {
+     }
+ 
+     /// Optimal transfer block size
+-    #[cfg(any(target_os = "ios", target_os = "macos", target_os = "openbsd"))]
++    #[cfg(any(target_os = "ios", target_os = "macos"))]
+     pub fn optimal_transfer_size(&self) -> i32 {
+         self.0.f_iosize
+     }
+ 
+     /// Optimal transfer block size
+-    #[cfg(all(target_os = "linux", target_arch = "s390x"))]
++    #[cfg(target_os = "openbsd")]
+     pub fn optimal_transfer_size(&self) -> u32 {
+-        self.0.f_bsize
++        self.0.f_iosize
+     }
+ 
+     /// Optimal transfer block size
+-    #[cfg(all(target_os = "linux", target_env = "musl"))]
+-    pub fn optimal_transfer_size(&self) -> libc::c_ulong {
++    #[cfg(all(target_os = "linux", target_arch = "s390x"))]
++    pub fn optimal_transfer_size(&self) -> u32 {
+         self.0.f_bsize
+     }
+ 
+     /// 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 {
++    #[cfg(any(
++        target_os = "android",
++        all(target_os = "linux", target_env = "musl")
++    ))]
++    pub fn optimal_transfer_size(&self) -> libc::c_ulong {
+         self.0.f_bsize
+     }
+ 
+     /// Optimal transfer block size
+-    #[cfg(target_os = "android")]
+-    pub fn optimal_transfer_size(&self) -> libc::c_ulong {
++    #[cfg(all(target_os = "linux", not(any(target_arch = "s390x", target_env = "musl"))))]
++    pub fn optimal_transfer_size(&self) -> libc::__fsword_t {
+         self.0.f_bsize
+     }
+ 
+@@ -169,7 +183,7 @@ impl Statfs {
+     /// 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
+     }
+ 
+@@ -211,7 +225,7 @@ impl Statfs {
+ 
+     /// 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
+     }
+ 
+@@ -240,7 +254,7 @@ impl Statfs {
+     }
+ 
+     /// 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
+     }
+@@ -253,7 +267,7 @@ impl Statfs {
+         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
+@@ -278,7 +292,7 @@ impl Statfs {
+     }
+ 
+     /// 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
+     }
+@@ -291,7 +305,7 @@ impl Statfs {
+         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
+@@ -316,7 +330,7 @@ impl Statfs {
+     }
+ 
+     /// 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
+     }
+@@ -329,7 +343,7 @@ impl Statfs {
+         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
+@@ -354,8 +368,8 @@ impl Statfs {
+     }
+ 
+     /// 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
+     }
+ 
+@@ -367,14 +381,19 @@ impl Statfs {
+         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
+     }
+ 
+     /// Free file nodes in filesystem
+-    #[cfg(any(target_os = "ios", target_os = "macos", target_os = "android"))]
++    #[cfg(any(
++            target_os = "android",
++            target_os = "ios",
++            target_os = "macos",
++            target_os = "openbsd"
++    ))]
+     pub fn files_free(&self) -> u64 {
+         self.0.f_ffree
+     }
+@@ -386,14 +405,14 @@ impl Statfs {
+     }
+ 
+     /// Free file nodes in filesystem
+-    #[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
++    #[cfg(target_os = "freebsd")]
+     pub fn files_free(&self) -> i64 {
+         self.0.f_ffree
+     }
+ 
+     /// Free file nodes in filesystem
+-    #[cfg(all(target_os = "linux", target_env = "musl"))]
+-    pub fn files_free(&self) -> u64 {
++    #[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
+     }
+ 
+@@ -405,7 +424,7 @@ impl Statfs {
+         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
+@@ -434,16 +453,17 @@ impl Debug for Statfs {
+ 
+ pub fn statfs<P: ?Sized + NixPath>(path: &P) -> Result<Statfs> {
+     unsafe {
+-        let mut stat: Statfs = mem::uninitialized();
+-        let res = path.with_nix_path(|path| libc::statfs(path.as_ptr(), &mut stat.0))?;
+-        Errno::result(res).map(|_| stat)
++        let mut stat = mem::MaybeUninit::<libc::statfs>::uninit();
++        let res = path.with_nix_path(|path| libc::statfs(path.as_ptr(), stat.as_mut_ptr()))?;
++        Errno::result(res).map(|_| Statfs(stat.assume_init()))
+     }
+ }
+ 
+ pub fn fstatfs<T: AsRawFd>(fd: &T) -> Result<Statfs> {
+     unsafe {
+-        let mut stat: Statfs = mem::uninitialized();
+-        Errno::result(libc::fstatfs(fd.as_raw_fd(), &mut stat.0)).map(|_| stat)
++        let mut stat = mem::MaybeUninit::<libc::statfs>::uninit();
++        Errno::result(libc::fstatfs(fd.as_raw_fd(), stat.as_mut_ptr()))
++            .map(|_| Statfs(stat.assume_init()))
+     }
+ }
+ 
+@@ -451,8 +471,8 @@ pub fn fstatfs<T: AsRawFd>(fd: &T) -> Result<Statfs> {
+ mod test {
+     use std::fs::File;
+ 
+-    use sys::statfs::*;
+-    use sys::statvfs::*;
++    use crate::sys::statfs::*;
++    use crate::sys::statvfs::*;
+     use std::path::Path;
+ 
+     #[test]
+diff --git a/third_party/rust/nix/src/sys/statvfs.rs b/third_party/rust/nix/src/sys/statvfs.rs
+index e5980369d5119..9bea9734925f0 100644
+--- a/third_party/rust/nix/src/sys/statvfs.rs
++++ b/third_party/rust/nix/src/sys/statvfs.rs
+@@ -7,9 +7,9 @@ use std::os::unix::io::AsRawFd;
+ 
+ use libc::{self, c_ulong};
+ 
+-use {Result, NixPath};
+-use errno::Errno;
++use crate::{Result, NixPath, errno::Errno};
+ 
++#[cfg(not(target_os = "redox"))]
+ libc_bitflags!(
+     /// File system mount Flags
+     #[repr(C)]
+@@ -55,8 +55,7 @@ libc_bitflags!(
+ /// Wrapper around the POSIX `statvfs` struct
+ ///
+ /// For more information see the [`statvfs(3)` man pages](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_statvfs.h.html).
+-// FIXME: Replace with repr(transparent)
+-#[repr(C)]
++#[repr(transparent)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+ pub struct Statvfs(libc::statvfs);
+ 
+@@ -109,6 +108,7 @@ impl Statvfs {
+     }
+ 
+     /// Get the mount flags
++    #[cfg(not(target_os = "redox"))]
+     pub fn flags(&self) -> FsFlags {
+         FsFlags::from_bits_truncate(self.0.f_flag)
+     }
+@@ -124,12 +124,12 @@ impl Statvfs {
+ pub fn statvfs<P: ?Sized + NixPath>(path: &P) -> Result<Statvfs> {
+     unsafe {
+         Errno::clear();
+-        let mut stat: Statvfs = mem::uninitialized();
++        let mut stat = mem::MaybeUninit::<libc::statvfs>::uninit();
+         let res = path.with_nix_path(|path|
+-            libc::statvfs(path.as_ptr(), &mut stat.0)
++            libc::statvfs(path.as_ptr(), stat.as_mut_ptr())
+         )?;
+ 
+-        Errno::result(res).map(|_| stat)
++        Errno::result(res).map(|_| Statvfs(stat.assume_init()))
+     }
+ }
+ 
+@@ -137,15 +137,16 @@ pub fn statvfs<P: ?Sized + NixPath>(path: &P) -> Result<Statvfs> {
+ pub fn fstatvfs<T: AsRawFd>(fd: &T) -> Result<Statvfs> {
+     unsafe {
+         Errno::clear();
+-        let mut stat: Statvfs = mem::uninitialized();
+-        Errno::result(libc::fstatvfs(fd.as_raw_fd(), &mut stat.0)).map(|_| stat)
++        let mut stat = mem::MaybeUninit::<libc::statvfs>::uninit();
++        Errno::result(libc::fstatvfs(fd.as_raw_fd(), stat.as_mut_ptr()))
++            .map(|_| Statvfs(stat.assume_init()))
+     }
+ }
+ 
+ #[cfg(test)]
+ mod test {
+     use std::fs::File;
+-    use sys::statvfs::*;
++    use crate::sys::statvfs::*;
+ 
+     #[test]
+     fn statvfs_call() {
+diff --git a/third_party/rust/nix/src/sys/sysinfo.rs b/third_party/rust/nix/src/sys/sysinfo.rs
+index 4c8e38988886d..222a2fc0480c3 100644
+--- a/third_party/rust/nix/src/sys/sysinfo.rs
++++ b/third_party/rust/nix/src/sys/sysinfo.rs
+@@ -2,13 +2,20 @@ use libc::{self, SI_LOAD_SHIFT};
+ use std::{cmp, mem};
+ use std::time::Duration;
+ 
+-use Result;
+-use errno::Errno;
++use crate::Result;
++use crate::errno::Errno;
+ 
+ /// System info structure returned by `sysinfo`.
+ #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
++#[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.
+     ///
+@@ -57,7 +64,7 @@ impl SysInfo {
+         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
+     }
+ }
+@@ -66,7 +73,7 @@ impl SysInfo {
+ ///
+ /// [See `sysinfo(2)`](http://man7.org/linux/man-pages/man2/sysinfo.2.html).
+ pub fn sysinfo() -> Result<SysInfo> {
+-    let mut info: libc::sysinfo = unsafe { mem::uninitialized() };
+-    let res = unsafe { libc::sysinfo(&mut info) };
+-    Errno::result(res).map(|_| SysInfo(info))
++    let mut info = mem::MaybeUninit::uninit();
++    let res = unsafe { libc::sysinfo(info.as_mut_ptr()) };
++    Errno::result(res).map(|_| unsafe{ SysInfo(info.assume_init()) })
+ }
+diff --git a/third_party/rust/nix/src/sys/termios.rs b/third_party/rust/nix/src/sys/termios.rs
+index c7cdf10b461c1..95148360495f1 100644
+--- a/third_party/rust/nix/src/sys/termios.rs
++++ b/third_party/rust/nix/src/sys/termios.rs
+@@ -25,7 +25,7 @@
+ //! ```
+ //! # use self::nix::sys::termios::SpecialCharacterIndices::VEOF;
+ //! # use self::nix::sys::termios::{_POSIX_VDISABLE, Termios};
+-//! # let mut termios = unsafe { Termios::default_uninit() };
++//! # let mut termios: Termios = unsafe { std::mem::zeroed() };
+ //! termios.control_chars[VEOF as usize] = _POSIX_VDISABLE;
+ //! ```
+ //!
+@@ -38,7 +38,7 @@
+ //!
+ //! ```
+ //! # use self::nix::sys::termios::{ControlFlags, Termios};
+-//! # let mut termios = unsafe { Termios::default_uninit() };
++//! # let mut termios: Termios = unsafe { std::mem::zeroed() };
+ //! termios.control_flags & ControlFlags::CSIZE == ControlFlags::CS5;
+ //! termios.control_flags |= ControlFlags::CS5;
+ //! ```
+@@ -61,10 +61,9 @@
+ //! platforms:
+ //!
+ //! ```rust
+-//! # #[macro_use] extern crate nix;
+ //! # use nix::sys::termios::{BaudRate, cfsetispeed, cfsetospeed, cfsetspeed, Termios};
+ //! # fn main() {
+-//! # let mut t = unsafe { Termios::default_uninit() };
++//! # let mut t: Termios = unsafe { std::mem::zeroed() };
+ //! cfsetispeed(&mut t, BaudRate::B9600);
+ //! cfsetospeed(&mut t, BaudRate::B9600);
+ //! cfsetspeed(&mut t, BaudRate::B9600);
+@@ -74,102 +73,94 @@
+ //! Additionally round-tripping baud rates is consistent across platforms:
+ //!
+ //! ```rust
+-//! # extern crate nix;
+ //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetispeed, cfsetspeed, Termios};
+ //! # fn main() {
+-//! # let mut t = unsafe { Termios::default_uninit() };
++//! # let mut t: Termios = unsafe { std::mem::zeroed() };
+ //! # cfsetspeed(&mut t, BaudRate::B9600);
+ //! let speed = cfgetispeed(&t);
+-//! assert!(speed == cfgetospeed(&t));
++//! assert_eq!(speed, cfgetospeed(&t));
+ //! cfsetispeed(&mut t, speed);
+ //! # }
+ //! ```
+ //!
+ //! On non-BSDs, `cfgetispeed()` and `cfgetospeed()` both return a `BaudRate`:
+ //!
+-// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version
+ #![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+                 target_os = "macos", target_os = "netbsd", target_os = "openbsd"),
+             doc = " ```rust,ignore")]
+ #![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+                     target_os = "macos", target_os = "netbsd", target_os = "openbsd")),
+             doc = " ```rust")]
+-//! # extern crate nix;
+ //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios};
+ //! # fn main() {
+-//! # let mut t = unsafe { Termios::default_uninit() };
++//! # let mut t: Termios = unsafe { std::mem::zeroed() };
+ //! # cfsetspeed(&mut t, BaudRate::B9600);
+-//! assert!(cfgetispeed(&t) == BaudRate::B9600);
+-//! assert!(cfgetospeed(&t) == BaudRate::B9600);
++//! assert_eq!(cfgetispeed(&t), BaudRate::B9600);
++//! assert_eq!(cfgetospeed(&t), BaudRate::B9600);
+ //! # }
+ //! ```
+ //!
+ //! But on the BSDs, `cfgetispeed()` and `cfgetospeed()` both return `u32`s:
+ //!
+-// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version
+ #![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+                 target_os = "macos", target_os = "netbsd", target_os = "openbsd"),
+             doc = " ```rust")]
+ #![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+                     target_os = "macos", target_os = "netbsd", target_os = "openbsd")),
+             doc = " ```rust,ignore")]
+-//! # extern crate nix;
+ //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfgetospeed, cfsetspeed, Termios};
+ //! # fn main() {
+-//! # let mut t = unsafe { Termios::default_uninit() };
++//! # let mut t: Termios = unsafe { std::mem::zeroed() };
+ //! # cfsetspeed(&mut t, 9600u32);
+-//! assert!(cfgetispeed(&t) == 9600u32);
+-//! assert!(cfgetospeed(&t) == 9600u32);
++//! assert_eq!(cfgetispeed(&t), 9600u32);
++//! assert_eq!(cfgetospeed(&t), 9600u32);
+ //! # }
+ //! ```
+ //!
+ //! It's trivial to convert from a `BaudRate` to a `u32` on BSDs:
+ //!
+-// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version
+ #![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+                 target_os = "macos", target_os = "netbsd", target_os = "openbsd"),
+             doc = " ```rust")]
+ #![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+                     target_os = "macos", target_os = "netbsd", target_os = "openbsd")),
+             doc = " ```rust,ignore")]
+-//! # extern crate nix;
+ //! # use nix::sys::termios::{BaudRate, cfgetispeed, cfsetspeed, Termios};
+ //! # fn main() {
+-//! # let mut t = unsafe { Termios::default_uninit() };
++//! # let mut t: Termios = unsafe { std::mem::zeroed() };
+ //! # cfsetspeed(&mut t, 9600u32);
+-//! assert!(cfgetispeed(&t) == BaudRate::B9600.into());
+-//! assert!(u32::from(BaudRate::B9600) == 9600u32);
++//! assert_eq!(cfgetispeed(&t), BaudRate::B9600.into());
++//! assert_eq!(u32::from(BaudRate::B9600), 9600u32);
+ //! # }
+ //! ```
+ //!
+ //! And on BSDs you can specify arbitrary baud rates (**note** this depends on hardware support)
+ //! by specifying baud rates directly using `u32`s:
+ //!
+-// FIXME: Replace `ignore` with `compile_fail` once 1.22 is the minimum support Rust version
+ #![cfg_attr(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+                 target_os = "macos", target_os = "netbsd", target_os = "openbsd"),
+             doc = " ```rust")]
+ #![cfg_attr(not(any(target_os = "freebsd", target_os = "dragonfly", target_os = "ios",
+                     target_os = "macos", target_os = "netbsd", target_os = "openbsd")),
+             doc = " ```rust,ignore")]
+-//! # extern crate nix;
+ //! # use nix::sys::termios::{cfsetispeed, cfsetospeed, cfsetspeed, Termios};
+ //! # fn main() {
+-//! # let mut t = unsafe { Termios::default_uninit() };
++//! # let mut t: Termios = unsafe { std::mem::zeroed() };
+ //! cfsetispeed(&mut t, 9600u32);
+ //! cfsetospeed(&mut t, 9600u32);
+ //! cfsetspeed(&mut t, 9600u32);
+ //! # }
+ //! ```
+-use Result;
+-use errno::Errno;
++use cfg_if::cfg_if;
++use crate::{Error, Result};
++use crate::errno::Errno;
+ use libc::{self, c_int, tcflag_t};
+ use std::cell::{Ref, RefCell};
+-use std::convert::From;
++use std::convert::{From, TryFrom};
+ use std::mem;
+ use std::os::unix::io::RawFd;
+ 
+-use ::unistd::Pid;
++use crate::unistd::Pid;
+ 
+ /// Stores settings for the termios API
+ ///
+@@ -194,24 +185,9 @@ pub struct Termios {
+ impl Termios {
+     /// Exposes an immutable reference to the underlying `libc::termios` data structure.
+     ///
+-    /// This can be used for interfacing with other FFI functions like:
+-    ///
+-    /// ```rust
+-    /// # extern crate libc;
+-    /// # extern crate nix;
+-    /// # fn main() {
+-    /// # use nix::sys::termios::Termios;
+-    /// # let mut termios = unsafe { Termios::default_uninit() };
+-    /// let inner_termios = termios.get_libc_termios();
+-    /// unsafe { libc::cfgetispeed(&*inner_termios) };
+-    /// # }
+-    /// ```
+-    ///
+-    /// There is no public API exposed for functions that modify the underlying `libc::termios`
+-    /// data because it requires additional work to maintain type safety.
+-    // FIXME: Switch this over to use pub(crate)
+-    #[doc(hidden)]
+-    pub fn get_libc_termios(&self) -> Ref<libc::termios> {
++    /// This is not part of `nix`'s public API because it requires additional work to maintain type
++    /// safety.
++    pub(crate) fn get_libc_termios(&self) -> Ref<libc::termios> {
+         {
+             let mut termios = self.inner.borrow_mut();
+             termios.c_iflag = self.input_flags.bits();
+@@ -225,12 +201,11 @@ impl Termios {
+ 
+     /// Exposes the inner `libc::termios` datastore within `Termios`.
+     ///
+-    /// This is unsafe because if this is used to modify the inner libc::termios struct, it will not
+-    /// automatically update the safe wrapper type around it. Therefore we disable docs to
+-    /// effectively limit its use to nix internals. In this case it should also be paired with a
+-    /// call to `update_wrapper()` so that the wrapper-type and internal representation stay
+-    /// consistent.
+-    unsafe fn get_libc_termios_mut(&mut self) -> *mut libc::termios {
++    /// This is unsafe because if this is used to modify the inner `libc::termios` struct, it will
++    /// not automatically update the safe wrapper type around it. In this case it should also be
++    /// paired with a call to `update_wrapper()` so that the wrapper-type and internal
++    /// representation stay consistent.
++    pub(crate) unsafe fn get_libc_termios_mut(&mut self) -> *mut libc::termios {
+         {
+             let mut termios = self.inner.borrow_mut();
+             termios.c_iflag = self.input_flags.bits();
+@@ -242,26 +217,8 @@ impl Termios {
+         self.inner.as_ptr()
+     }
+ 
+-    /// Allows for easily creating new `Termios` structs that will be overwritten with real data.
+-    ///
+-    /// This should only be used when the inner libc::termios struct will be overwritten before it's
+-    /// read.
+-    // FIXME: Switch this over to use pub(crate)
+-    #[doc(hidden)]
+-    pub unsafe fn default_uninit() -> Self {
+-        Termios {
+-            inner: RefCell::new(mem::uninitialized()),
+-            input_flags: InputFlags::empty(),
+-            output_flags: OutputFlags::empty(),
+-            control_flags: ControlFlags::empty(),
+-            local_flags: LocalFlags::empty(),
+-            control_chars: [0 as libc::cc_t; NCCS],
+-        }
+-    }
+-
+     /// Updates the wrapper values from the internal `libc::termios` data structure.
+-    #[doc(hidden)]
+-    pub fn update_wrapper(&mut self) {
++    pub(crate) fn update_wrapper(&mut self) {
+         let termios = *self.inner.borrow_mut();
+         self.input_flags = InputFlags::from_bits_truncate(termios.c_iflag);
+         self.output_flags = OutputFlags::from_bits_truncate(termios.c_oflag);
+@@ -376,9 +333,10 @@ libc_enum!{
+     }
+ }
+ 
+-impl From<libc::speed_t> for BaudRate {
+-    fn from(s: libc::speed_t) -> BaudRate {
++impl TryFrom<libc::speed_t> for BaudRate {
++    type Error = Error;
+ 
++    fn try_from(s: libc::speed_t) -> Result<BaudRate> {
+         use libc::{B0, B50, B75, B110, B134, B150, B200, B300, B600, B1200, B1800, B2400, B4800,
+                    B9600, B19200, B38400, B57600, B115200, B230400};
+         #[cfg(any(target_os = "android", target_os = "linux"))]
+@@ -398,85 +356,84 @@ impl From<libc::speed_t> for BaudRate {
+         use libc::{B460800, B921600};
+ 
+         match s {
+-            B0 => BaudRate::B0,
+-            B50 => BaudRate::B50,
+-            B75 => BaudRate::B75,
+-            B110 => BaudRate::B110,
+-            B134 => BaudRate::B134,
+-            B150 => BaudRate::B150,
+-            B200 => BaudRate::B200,
+-            B300 => BaudRate::B300,
+-            B600 => BaudRate::B600,
+-            B1200 => BaudRate::B1200,
+-            B1800 => BaudRate::B1800,
+-            B2400 => BaudRate::B2400,
+-            B4800 => BaudRate::B4800,
++            B0 => Ok(BaudRate::B0),
++            B50 => Ok(BaudRate::B50),
++            B75 => Ok(BaudRate::B75),
++            B110 => Ok(BaudRate::B110),
++            B134 => Ok(BaudRate::B134),
++            B150 => Ok(BaudRate::B150),
++            B200 => Ok(BaudRate::B200),
++            B300 => Ok(BaudRate::B300),
++            B600 => Ok(BaudRate::B600),
++            B1200 => Ok(BaudRate::B1200),
++            B1800 => Ok(BaudRate::B1800),
++            B2400 => Ok(BaudRate::B2400),
++            B4800 => Ok(BaudRate::B4800),
+             #[cfg(any(target_os = "dragonfly",
+                       target_os = "freebsd",
+                       target_os = "macos",
+                       target_os = "netbsd",
+                       target_os = "openbsd"))]
+-            B7200 => BaudRate::B7200,
+-            B9600 => BaudRate::B9600,
++            B7200 => Ok(BaudRate::B7200),
++            B9600 => Ok(BaudRate::B9600),
+             #[cfg(any(target_os = "dragonfly",
+                       target_os = "freebsd",
+                       target_os = "macos",
+                       target_os = "netbsd",
+                       target_os = "openbsd"))]
+-            B14400 => BaudRate::B14400,
+-            B19200 => BaudRate::B19200,
++            B14400 => Ok(BaudRate::B14400),
++            B19200 => Ok(BaudRate::B19200),
+             #[cfg(any(target_os = "dragonfly",
+                       target_os = "freebsd",
+                       target_os = "macos",
+                       target_os = "netbsd",
+                       target_os = "openbsd"))]
+-            B28800 => BaudRate::B28800,
+-            B38400 => BaudRate::B38400,
+-            B57600 => BaudRate::B57600,
++            B28800 => Ok(BaudRate::B28800),
++            B38400 => Ok(BaudRate::B38400),
++            B57600 => Ok(BaudRate::B57600),
+             #[cfg(any(target_os = "dragonfly",
+                       target_os = "freebsd",
+                       target_os = "macos",
+                       target_os = "netbsd",
+                       target_os = "openbsd"))]
+-            B76800 => BaudRate::B76800,
+-            B115200 => BaudRate::B115200,
+-            B230400 => BaudRate::B230400,
++            B76800 => Ok(BaudRate::B76800),
++            B115200 => Ok(BaudRate::B115200),
++            B230400 => Ok(BaudRate::B230400),
+             #[cfg(any(target_os = "android",
+                       target_os = "freebsd",
+                       target_os = "linux",
+                       target_os = "netbsd"))]
+-            B460800 => BaudRate::B460800,
++            B460800 => Ok(BaudRate::B460800),
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            B500000 => BaudRate::B500000,
++            B500000 => Ok(BaudRate::B500000),
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            B576000 => BaudRate::B576000,
++            B576000 => Ok(BaudRate::B576000),
+             #[cfg(any(target_os = "android",
+                       target_os = "freebsd",
+                       target_os = "linux",
+                       target_os = "netbsd"))]
+-            B921600 => BaudRate::B921600,
++            B921600 => Ok(BaudRate::B921600),
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            B1000000 => BaudRate::B1000000,
++            B1000000 => Ok(BaudRate::B1000000),
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            B1152000 => BaudRate::B1152000,
++            B1152000 => Ok(BaudRate::B1152000),
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            B1500000 => BaudRate::B1500000,
++            B1500000 => Ok(BaudRate::B1500000),
+             #[cfg(any(target_os = "android", target_os = "linux"))]
+-            B2000000 => BaudRate::B2000000,
++            B2000000 => Ok(BaudRate::B2000000),
+             #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
+-            B2500000 => BaudRate::B2500000,
++            B2500000 => Ok(BaudRate::B2500000),
+             #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
+-            B3000000 => BaudRate::B3000000,
++            B3000000 => Ok(BaudRate::B3000000),
+             #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
+-            B3500000 => BaudRate::B3500000,
++            B3500000 => Ok(BaudRate::B3500000),
+             #[cfg(any(target_os = "android", all(target_os = "linux", not(target_arch = "sparc64"))))]
+-            B4000000 => BaudRate::B4000000,
+-            b => unreachable!("Invalid baud constant: {}", b),
++            B4000000 => Ok(BaudRate::B4000000),
++            _ => Err(Error::invalid_argument())
+         }
+     }
+ }
+ 
+-// TODO: Include `TryFrom<u32> for BaudRate` once that API stabilizes
+ #[cfg(any(target_os = "freebsd",
+           target_os = "dragonfly",
+           target_os = "ios",
+@@ -583,6 +540,12 @@ libc_enum! {
+     }
+ }
+ 
++#[cfg(all(target_os = "linux", target_arch = "sparc64"))]
++impl SpecialCharacterIndices {
++    pub const VMIN: SpecialCharacterIndices = SpecialCharacterIndices::VEOF;
++    pub const VTIME: SpecialCharacterIndices = SpecialCharacterIndices::VEOL;
++}
++
+ pub use libc::NCCS;
+ #[cfg(any(target_os = "dragonfly",
+           target_os = "freebsd",
+@@ -606,7 +569,9 @@ libc_bitflags! {
+         ICRNL;
+         IXON;
+         IXOFF;
++        #[cfg(not(target_os = "redox"))]
+         IXANY;
++        #[cfg(not(target_os = "redox"))]
+         IMAXBEL;
+         #[cfg(any(target_os = "android", target_os = "linux", target_os = "macos"))]
+         IUTF8;
+@@ -816,6 +781,7 @@ libc_bitflags! {
+         PARODD;
+         HUPCL;
+         CLOCAL;
++        #[cfg(not(target_os = "redox"))]
+         CRTSCTS;
+         #[cfg(any(target_os = "android", target_os = "linux"))]
+         CBAUD;
+@@ -866,12 +832,15 @@ libc_bitflags! {
+ libc_bitflags! {
+     /// Flags for setting any local modes
+     pub struct LocalFlags: tcflag_t {
++        #[cfg(not(target_os = "redox"))]
+         ECHOKE;
+         ECHOE;
+         ECHOK;
+         ECHO;
+         ECHONL;
++        #[cfg(not(target_os = "redox"))]
+         ECHOPRT;
++        #[cfg(not(target_os = "redox"))]
+         ECHOCTL;
+         ISIG;
+         ICANON;
+@@ -883,8 +852,10 @@ libc_bitflags! {
+                   target_os = "openbsd"))]
+         ALTWERASE;
+         IEXTEN;
++        #[cfg(not(target_os = "redox"))]
+         EXTPROC;
+         TOSTOP;
++        #[cfg(not(target_os = "redox"))]
+         FLUSHO;
+         #[cfg(any(target_os = "freebsd",
+                   target_os = "dragonfly",
+@@ -893,6 +864,7 @@ libc_bitflags! {
+                   target_os = "netbsd",
+                   target_os = "openbsd"))]
+         NOKERNINFO;
++        #[cfg(not(target_os = "redox"))]
+         PENDIN;
+         NOFLSH;
+     }
+@@ -957,13 +929,15 @@ cfg_if!{
+             Errno::result(res).map(drop)
+         }
+     } else {
++        use std::convert::TryInto;
++
+         /// Get input baud rate (see
+         /// [cfgetispeed(3p)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)).
+         ///
+         /// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure.
+         pub fn cfgetispeed(termios: &Termios) -> BaudRate {
+             let inner_termios = termios.get_libc_termios();
+-            unsafe { libc::cfgetispeed(&*inner_termios) }.into()
++            unsafe { libc::cfgetispeed(&*inner_termios) }.try_into().unwrap()
+         }
+ 
+         /// Get output baud rate (see
+@@ -972,7 +946,7 @@ cfg_if!{
+         /// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure.
+         pub fn cfgetospeed(termios: &Termios) -> BaudRate {
+             let inner_termios = termios.get_libc_termios();
+-            unsafe { libc::cfgetospeed(&*inner_termios) }.into()
++            unsafe { libc::cfgetospeed(&*inner_termios) }.try_into().unwrap()
+         }
+ 
+         /// Set input baud rate (see
+@@ -1045,13 +1019,13 @@ pub fn cfmakesane(termios: &mut Termios) {
+ /// this structure *will not* reconfigure the port, instead the modifications should be done to
+ /// the `Termios` structure and then the port should be reconfigured using `tcsetattr()`.
+ pub fn tcgetattr(fd: RawFd) -> Result<Termios> {
+-    let mut termios: libc::termios = unsafe { mem::uninitialized() };
++    let mut termios = mem::MaybeUninit::uninit();
+ 
+-    let res = unsafe { libc::tcgetattr(fd, &mut termios) };
++    let res = unsafe { libc::tcgetattr(fd, termios.as_mut_ptr()) };
+ 
+     Errno::result(res)?;
+ 
+-    Ok(termios.into())
++    unsafe { Ok(termios.assume_init().into()) }
+ }
+ 
+ /// Set the configuration for a terminal (see
+@@ -1105,3 +1079,14 @@ pub fn tcgetsid(fd: RawFd) -> Result<Pid> {
+ 
+     Errno::result(res).map(Pid::from_raw)
+ }
++
++#[cfg(test)]
++mod test {
++    use super::*;
++
++    #[test]
++    fn try_from() {
++        assert_eq!(Ok(BaudRate::B0), BaudRate::try_from(libc::B0));
++        assert!(BaudRate::try_from(999999999).is_err());
++    }
++}
+diff --git a/third_party/rust/nix/src/sys/time.rs b/third_party/rust/nix/src/sys/time.rs
+index 3ad57543b18a7..7546d1b367c5e 100644
+--- a/third_party/rust/nix/src/sys/time.rs
++++ b/third_party/rust/nix/src/sys/time.rs
+@@ -1,6 +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 {
+@@ -60,6 +62,34 @@ const TS_MAX_SECONDS: i64 = ::std::isize::MAX as i64;
+ 
+ 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)
++    }
++}
++
++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 timespec_tv_nsec_t
++        })
++    }
++}
++
++impl From<TimeSpec> for Duration {
++    fn from(timespec: TimeSpec) -> Self {
++        Duration::new(timespec.0.tv_sec as u64, timespec.0.tv_nsec as u32)
++    }
++}
+ 
+ impl AsRef<timespec> for TimeSpec {
+     fn as_ref(&self) -> &timespec {
+@@ -67,6 +97,12 @@ impl AsRef<timespec> for TimeSpec {
+     }
+ }
+ 
++impl AsMut<timespec> for TimeSpec {
++    fn as_mut(&mut self) -> &mut timespec {
++        &mut self.0
++    }
++}
++
+ impl Ord for TimeSpec {
+     // The implementation of cmp is simplified by assuming that the struct is
+     // normalized.  That is, tv_nsec must always be within [0, 1_000_000_000)
+@@ -90,6 +126,7 @@ impl TimeValLike for TimeSpec {
+     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 })
+     }
+ 
+@@ -116,8 +153,9 @@ impl TimeValLike for TimeSpec {
+         let (secs, nanos) = div_mod_floor_64(nanoseconds, NANOS_PER_SEC);
+         assert!(secs >= TS_MIN_SECONDS && secs <= TS_MAX_SECONDS,
+                 "TimeSpec out of bounds");
++        #[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 {
+@@ -144,19 +182,20 @@ impl TimeValLike for TimeSpec {
+ }
+ 
+ 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
+     }
+ }
+@@ -191,7 +230,7 @@ impl ops::Mul<i32> for TimeSpec {
+     type Output = TimeSpec;
+ 
+     fn mul(self, rhs: i32) -> TimeSpec {
+-        let usec = self.num_nanoseconds().checked_mul(rhs as i64)
++        let usec = self.num_nanoseconds().checked_mul(i64::from(rhs))
+             .expect("TimeSpec multiply out of bounds");
+ 
+         TimeSpec::nanoseconds(usec)
+@@ -202,7 +241,7 @@ impl ops::Div<i32> for TimeSpec {
+     type Output = TimeSpec;
+ 
+     fn div(self, rhs: i32) -> TimeSpec {
+-        let usec = self.num_nanoseconds() / rhs as i64;
++        let usec = self.num_nanoseconds() / i64::from(rhs);
+         TimeSpec::nanoseconds(usec)
+     }
+ }
+@@ -239,7 +278,7 @@ impl fmt::Display for TimeSpec {
+ 
+ 
+ 
+-#[repr(C)]
++#[repr(transparent)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+ pub struct TimeVal(timeval);
+ 
+@@ -259,6 +298,12 @@ impl AsRef<timeval> for TimeVal {
+     }
+ }
+ 
++impl AsMut<timeval> for TimeVal {
++    fn as_mut(&mut self) -> &mut timeval {
++        &mut self.0
++    }
++}
++
+ impl Ord for TimeVal {
+     // The implementation of cmp is simplified by assuming that the struct is
+     // normalized.  That is, tv_usec must always be within [0, 1_000_000)
+@@ -282,6 +327,7 @@ impl TimeValLike for TimeVal {
+     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 })
+     }
+ 
+@@ -299,6 +345,7 @@ impl TimeValLike for TimeVal {
+         let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
+         assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS,
+                 "TimeVal out of bounds");
++        #[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 })
+     }
+@@ -311,6 +358,7 @@ impl TimeValLike for TimeVal {
+         let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
+         assert!(secs >= TV_MIN_SECONDS && secs <= TV_MAX_SECONDS,
+                 "TimeVal out of bounds");
++        #[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 })
+     }
+@@ -347,6 +395,7 @@ impl TimeVal {
+         }
+     }
+ 
++    #[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
+     }
+@@ -386,7 +435,7 @@ impl ops::Mul<i32> for TimeVal {
+     type Output = TimeVal;
+ 
+     fn mul(self, rhs: i32) -> TimeVal {
+-        let usec = self.num_microseconds().checked_mul(rhs as i64)
++        let usec = self.num_microseconds().checked_mul(i64::from(rhs))
+             .expect("TimeVal multiply out of bounds");
+ 
+         TimeVal::microseconds(usec)
+@@ -397,7 +446,7 @@ impl ops::Div<i32> for TimeVal {
+     type Output = TimeVal;
+ 
+     fn div(self, rhs: i32) -> TimeVal {
+-        let usec = self.num_microseconds() / rhs as i64;
++        let usec = self.num_microseconds() / i64::from(rhs);
+         TimeVal::microseconds(usec)
+     }
+ }
+@@ -467,6 +516,7 @@ fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
+ #[cfg(test)]
+ mod test {
+     use super::{TimeSpec, TimeVal, TimeValLike};
++    use std::time::Duration;
+ 
+     #[test]
+     pub fn test_timespec() {
+@@ -477,6 +527,15 @@ mod test {
+                    TimeSpec::seconds(182));
+     }
+ 
++    #[test]
++    pub fn test_timespec_from() {
++        let duration = Duration::new(123, 123_456_789);
++        let timespec = TimeSpec::nanoseconds(123_123_456_789);
++
++        assert_eq!(TimeSpec::from(duration), timespec);
++        assert_eq!(Duration::from(timespec), duration);
++    }
++
+     #[test]
+     pub fn test_timespec_neg() {
+         let a = TimeSpec::seconds(1) + TimeSpec::nanoseconds(123);
+diff --git a/third_party/rust/nix/src/sys/timerfd.rs b/third_party/rust/nix/src/sys/timerfd.rs
+new file mode 100644
+index 0000000000000..4a24719498602
+--- /dev/null
++++ b/third_party/rust/nix/src/sys/timerfd.rs
+@@ -0,0 +1,285 @@
++//! Timer API via file descriptors.
++//!
++//! Timer FD is a Linux-only API to create timers and get expiration
++//! notifications through file descriptors.
++//!
++//! For more documentation, please read [timerfd_create(2)](http://man7.org/linux/man-pages/man2/timerfd_create.2.html).
++//!
++//! # Examples
++//!
++//! Create a new one-shot timer that expires after 1 second.
++//! ```
++//! # use std::os::unix::io::AsRawFd;
++//! # use nix::sys::timerfd::{TimerFd, ClockId, TimerFlags, TimerSetTimeFlags,
++//! #    Expiration};
++//! # use nix::sys::time::{TimeSpec, TimeValLike};
++//! # use nix::unistd::read;
++//! #
++//! // We create a new monotonic timer.
++//! let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty())
++//!     .unwrap();
++//!
++//! // We set a new one-shot timer in 1 seconds.
++//! timer.set(
++//!     Expiration::OneShot(TimeSpec::seconds(1)),
++//!     TimerSetTimeFlags::empty()
++//! ).unwrap();
++//!
++//! // We wait for the timer to expire.
++//! timer.wait().unwrap();
++//! ```
++use crate::sys::time::TimeSpec;
++use crate::unistd::read;
++use crate::{errno::Errno, Error, Result};
++use bitflags::bitflags;
++use libc::c_int;
++use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
++
++/// A timerfd instance. This is also a file descriptor, you can feed it to
++/// other interfaces consuming file descriptors, epoll for example.
++#[derive(Debug)]
++pub struct TimerFd {
++    fd: RawFd,
++}
++
++impl AsRawFd for TimerFd {
++    fn as_raw_fd(&self) -> RawFd {
++        self.fd
++    }
++}
++
++impl FromRawFd for TimerFd {
++    unsafe fn from_raw_fd(fd: RawFd) -> Self {
++        TimerFd { fd }
++    }
++}
++
++libc_enum! {
++    /// The type of the clock used to mark the progress of the timer. For more
++    /// details on each kind of clock, please refer to [timerfd_create(2)](http://man7.org/linux/man-pages/man2/timerfd_create.2.html).
++    #[repr(i32)]
++    pub enum ClockId {
++        CLOCK_REALTIME,
++        CLOCK_MONOTONIC,
++        CLOCK_BOOTTIME,
++        CLOCK_REALTIME_ALARM,
++        CLOCK_BOOTTIME_ALARM,
++    }
++}
++
++libc_bitflags! {
++    /// Additional flags to change the behaviour of the file descriptor at the
++    /// time of creation.
++    pub struct TimerFlags: c_int {
++        TFD_NONBLOCK;
++        TFD_CLOEXEC;
++    }
++}
++
++bitflags! {
++    /// Flags that are used for arming the timer.
++    pub struct TimerSetTimeFlags: libc::c_int {
++        const TFD_TIMER_ABSTIME = libc::TFD_TIMER_ABSTIME;
++    }
++}
++
++#[derive(Debug, Clone, Copy)]
++struct TimerSpec(libc::itimerspec);
++
++impl TimerSpec {
++    pub fn none() -> Self {
++        Self(libc::itimerspec {
++            it_interval: libc::timespec {
++                tv_sec: 0,
++                tv_nsec: 0,
++            },
++            it_value: libc::timespec {
++                tv_sec: 0,
++                tv_nsec: 0,
++            },
++        })
++    }
++}
++
++impl AsRef<libc::itimerspec> for TimerSpec {
++    fn as_ref(&self) -> &libc::itimerspec {
++        &self.0
++    }
++}
++
++impl From<Expiration> for TimerSpec {
++    fn from(expiration: Expiration) -> TimerSpec {
++        match expiration {
++            Expiration::OneShot(t) => TimerSpec(libc::itimerspec {
++                it_interval: libc::timespec {
++                    tv_sec: 0,
++                    tv_nsec: 0,
++                },
++                it_value: *t.as_ref(),
++            }),
++            Expiration::IntervalDelayed(start, interval) => TimerSpec(libc::itimerspec {
++                it_interval: *interval.as_ref(),
++                it_value: *start.as_ref(),
++            }),
++            Expiration::Interval(t) => TimerSpec(libc::itimerspec {
++                it_interval: *t.as_ref(),
++                it_value: *t.as_ref(),
++            }),
++        }
++    }
++}
++
++impl From<TimerSpec> for Expiration {
++    fn from(timerspec: TimerSpec) -> Expiration {
++        match timerspec {
++            TimerSpec(libc::itimerspec {
++                it_interval:
++                    libc::timespec {
++                        tv_sec: 0,
++                        tv_nsec: 0,
++                    },
++                it_value: ts,
++            }) => Expiration::OneShot(ts.into()),
++            TimerSpec(libc::itimerspec {
++                it_interval: int_ts,
++                it_value: val_ts,
++            }) => {
++                if (int_ts.tv_sec == val_ts.tv_sec) && (int_ts.tv_nsec == val_ts.tv_nsec) {
++                    Expiration::Interval(int_ts.into())
++                } else {
++                    Expiration::IntervalDelayed(val_ts.into(), int_ts.into())
++                }
++            }
++        }
++    }
++}
++
++/// An enumeration allowing the definition of the expiration time of an alarm,
++/// recurring or not.
++#[derive(Debug, Clone, Copy, PartialEq)]
++pub enum Expiration {
++    OneShot(TimeSpec),
++    IntervalDelayed(TimeSpec, TimeSpec),
++    Interval(TimeSpec),
++}
++
++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). 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 })
++    }
++
++    /// Sets a new alarm on the timer.
++    ///
++    /// # Types of alarm
++    ///
++    /// There are 3 types of alarms you can set:
++    ///
++    ///   - one shot: the alarm will trigger once after the specified amount of
++    /// time.
++    ///     Example: I want an alarm to go off in 60s and then disables itself.
++    ///
++    ///   - interval: the alarm will trigger every specified interval of time.
++    ///     Example: I want an alarm to go off every 60s. The alarm will first
++    ///     go off 60s after I set it and every 60s after that. The alarm will
++    ///     not disable itself.
++    ///
++    ///   - interval delayed: the alarm will trigger after a certain amount of
++    ///     time and then trigger at a specified interval.
++    ///     Example: I want an alarm to go off every 60s but only start in 1h.
++    ///     The alarm will first trigger 1h after I set it and then every 60s
++    ///     after that. The alarm will not disable itself.
++    ///
++    /// # Relative vs absolute alarm
++    ///
++    /// If you do not set any `TimerSetTimeFlags`, then the `TimeSpec` you pass
++    /// to the `Expiration` you want is relative. If however you want an alarm
++    /// to go off at a certain point in time, you can set `TFD_TIMER_ABSTIME`.
++    /// Then the one shot TimeSpec and the delay TimeSpec of the delayed
++    /// interval are going to be interpreted as absolute.
++    ///
++    /// # Disabling alarms
++    ///
++    /// Note: Only one alarm can be set for any given timer. Setting a new alarm
++    /// actually removes the previous one.
++    ///
++    /// Note: Setting a one shot alarm with a 0s TimeSpec disables the alarm
++    /// altogether.
++    pub fn set(&self, expiration: Expiration, flags: TimerSetTimeFlags) -> Result<()> {
++        let timerspec: TimerSpec = expiration.into();
++        Errno::result(unsafe {
++            libc::timerfd_settime(
++                self.fd,
++                flags.bits(),
++                timerspec.as_ref(),
++                std::ptr::null_mut(),
++            )
++        })
++        .map(drop)
++    }
++
++    /// Get the parameters for the alarm currently set, if any.
++    pub fn get(&self) -> Result<Option<Expiration>> {
++        let mut timerspec = TimerSpec::none();
++        let timerspec_ptr: *mut libc::itimerspec = &mut timerspec.0;
++
++        Errno::result(unsafe { libc::timerfd_gettime(self.fd, timerspec_ptr) }).map(|_| {
++            if timerspec.0.it_interval.tv_sec == 0
++                && timerspec.0.it_interval.tv_nsec == 0
++                && timerspec.0.it_value.tv_sec == 0
++                && timerspec.0.it_value.tv_nsec == 0
++            {
++                None
++            } else {
++                Some(timerspec.into())
++            }
++        })
++    }
++
++    /// Remove the alarm if any is set.
++    pub fn unset(&self) -> Result<()> {
++        Errno::result(unsafe {
++            libc::timerfd_settime(
++                self.fd,
++                TimerSetTimeFlags::empty().bits(),
++                TimerSpec::none().as_ref(),
++                std::ptr::null_mut(),
++            )
++        })
++        .map(drop)
++    }
++
++    /// Wait for the configured alarm to expire.
++    ///
++    /// Note: If the alarm is unset, then you will wait forever.
++    pub fn wait(&self) -> Result<()> {
++        loop {
++            if let Err(e) = read(self.fd, &mut [0u8; 8]) {
++                match e {
++                    Error::Sys(Errno::EINTR) => continue,
++                    _ => return Err(e),
++                }
++            } else {
++                break;
++            }
++        }
++
++        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/third_party/rust/nix/src/sys/uio.rs b/third_party/rust/nix/src/sys/uio.rs
+index d089084eed711..65334227b4d1d 100644
+--- a/third_party/rust/nix/src/sys/uio.rs
++++ b/third_party/rust/nix/src/sys/uio.rs
+@@ -1,8 +1,8 @@
+ // Silence invalid warnings due to rust-lang/rust#16719
+ #![allow(improper_ctypes)]
+ 
+-use Result;
+-use errno::Errno;
++use crate::Result;
++use crate::errno::Errno;
+ use libc::{self, c_int, c_void, size_t, off_t};
+ use std::marker::PhantomData;
+ use std::os::unix::io::RawFd;
+@@ -117,7 +117,11 @@ pub struct RemoteIoVec {
+ /// [`IoVec`]: struct.IoVec.html
+ /// [`RemoteIoVec`]: struct.RemoteIoVec.html
+ #[cfg(target_os = "linux")]
+-pub fn process_vm_writev(pid: ::unistd::Pid, local_iov: &[IoVec<&[u8]>], remote_iov: &[RemoteIoVec]) -> Result<usize> {
++pub fn process_vm_writev(
++    pid: crate::unistd::Pid,
++    local_iov: &[IoVec<&[u8]>],
++    remote_iov: &[RemoteIoVec]) -> Result<usize>
++{
+     let res = unsafe {
+         libc::process_vm_writev(pid.into(),
+                                 local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong,
+@@ -148,7 +152,11 @@ pub fn process_vm_writev(pid: ::unistd::Pid, local_iov: &[IoVec<&[u8]>], remote_
+ /// [`IoVec`]: struct.IoVec.html
+ /// [`RemoteIoVec`]: struct.RemoteIoVec.html
+ #[cfg(any(target_os = "linux"))]
+-pub fn process_vm_readv(pid: ::unistd::Pid, local_iov: &[IoVec<&mut [u8]>], remote_iov: &[RemoteIoVec]) -> Result<usize> {
++pub fn process_vm_readv(
++    pid: crate::unistd::Pid,
++    local_iov: &[IoVec<&mut [u8]>],
++    remote_iov: &[RemoteIoVec]) -> Result<usize>
++{
+     let res = unsafe {
+         libc::process_vm_readv(pid.into(),
+                                local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong,
+@@ -158,7 +166,7 @@ pub fn process_vm_readv(pid: ::unistd::Pid, local_iov: &[IoVec<&mut [u8]>], remo
+     Errno::result(res).map(|r| r as usize)
+ }
+ 
+-#[repr(C)]
++#[repr(transparent)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+ pub struct IoVec<T>(libc::iovec, PhantomData<T>);
+ 
+diff --git a/third_party/rust/nix/src/sys/utsname.rs b/third_party/rust/nix/src/sys/utsname.rs
+index ab09c7d23232a..bf1a814d6d863 100644
+--- a/third_party/rust/nix/src/sys/utsname.rs
++++ b/third_party/rust/nix/src/sys/utsname.rs
+@@ -3,8 +3,8 @@ use libc::{self, c_char};
+ use std::ffi::CStr;
+ use std::str::from_utf8_unchecked;
+ 
+-#[repr(C)]
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
++#[repr(transparent)]
+ pub struct UtsName(libc::utsname);
+ 
+ impl UtsName {
+@@ -31,9 +31,9 @@ impl UtsName {
+ 
+ pub fn uname() -> UtsName {
+     unsafe {
+-        let mut ret: UtsName = mem::uninitialized();
+-        libc::uname(&mut ret.0);
+-        ret
++        let mut ret = mem::MaybeUninit::uninit();
++        libc::uname(ret.as_mut_ptr());
++        UtsName(ret.assume_init())
+     }
+ }
+ 
+diff --git a/third_party/rust/nix/src/sys/wait.rs b/third_party/rust/nix/src/sys/wait.rs
+index c54f7ec579667..faf8543cb1589 100644
+--- a/third_party/rust/nix/src/sys/wait.rs
++++ b/third_party/rust/nix/src/sys/wait.rs
+@@ -1,9 +1,10 @@
++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 Result;
+-use errno::Errno;
+-use unistd::Pid;
+-
+-use sys::signal::Signal;
++use std::convert::TryFrom;
+ 
+ libc_bitflags!(
+     pub struct WaitPidFlag: c_int {
+@@ -14,6 +15,7 @@ libc_bitflags!(
+                   target_os = "haiku",
+                   target_os = "ios",
+                   target_os = "linux",
++                  target_os = "redox",
+                   target_os = "macos",
+                   target_os = "netbsd"))]
+         WEXITED;
+@@ -23,6 +25,7 @@ libc_bitflags!(
+                   target_os = "haiku",
+                   target_os = "ios",
+                   target_os = "linux",
++                  target_os = "redox",
+                   target_os = "macos",
+                   target_os = "netbsd"))]
+         WSTOPPED;
+@@ -32,16 +35,17 @@ libc_bitflags!(
+                   target_os = "haiku",
+                   target_os = "ios",
+                   target_os = "linux",
++                  target_os = "redox",
+                   target_os = "macos",
+                   target_os = "netbsd"))]
+         WNOWAIT;
+         /// Don't wait on children of other threads in this group
+-        #[cfg(any(target_os = "android", target_os = "linux"))]
++        #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
+         __WNOTHREAD;
+         /// Wait on all children, regardless of type
+-        #[cfg(any(target_os = "android", target_os = "linux"))]
++        #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
+         __WALL;
+-        #[cfg(any(target_os = "android", target_os = "linux"))]
++        #[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
+         __WCLONE;
+     }
+ );
+@@ -104,8 +108,7 @@ impl WaitStatus {
+     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),
+@@ -114,31 +117,31 @@ impl WaitStatus {
+ }
+ 
+ fn exited(status: i32) -> bool {
+-    unsafe { libc::WIFEXITED(status) }
++    libc::WIFEXITED(status)
+ }
+ 
+ fn exit_status(status: i32) -> i32 {
+-    unsafe { libc::WEXITSTATUS(status) }
++    libc::WEXITSTATUS(status)
+ }
+ 
+ fn signaled(status: i32) -> bool {
+-    unsafe { libc::WIFSIGNALED(status) }
++    libc::WIFSIGNALED(status)
+ }
+ 
+ fn term_signal(status: i32) -> Result<Signal> {
+-    Signal::from_c_int(unsafe { libc::WTERMSIG(status) })
++    Signal::try_from(libc::WTERMSIG(status))
+ }
+ 
+ fn dumped_core(status: i32) -> bool {
+-    unsafe { libc::WCOREDUMP(status) }
++    libc::WCOREDUMP(status)
+ }
+ 
+ fn stopped(status: i32) -> bool {
+-    unsafe { libc::WIFSTOPPED(status) }
++    libc::WIFSTOPPED(status)
+ }
+ 
+ fn stop_signal(status: i32) -> Result<Signal> {
+-    Signal::from_c_int(unsafe { libc::WSTOPSIG(status) })
++    Signal::try_from(libc::WSTOPSIG(status))
+ }
+ 
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+@@ -147,7 +150,7 @@ fn syscall_stop(status: i32) -> bool {
+     // 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"))]
+@@ -156,7 +159,7 @@ fn stop_additional(status: i32) -> c_int {
+ }
+ 
+ fn continued(status: i32) -> bool {
+-    unsafe { libc::WIFCONTINUED(status) }
++    libc::WIFCONTINUED(status)
+ }
+ 
+ impl WaitStatus {
+@@ -222,7 +225,7 @@ pub fn waitpid<P: Into<Option<Pid>>>(pid: P, options: Option<WaitPidFlag>) -> Re
+ 
+     let res = unsafe {
+         libc::waitpid(
+-            pid.into().unwrap_or(Pid::from_raw(-1)).into(),
++            pid.into().unwrap_or_else(|| Pid::from_raw(-1)).into(),
+             &mut status as *mut c_int,
+             option_bits,
+         )
+diff --git a/third_party/rust/nix/src/time.rs b/third_party/rust/nix/src/time.rs
+new file mode 100644
+index 0000000000000..e6c3f8ded5a52
+--- /dev/null
++++ b/third_party/rust/nix/src/time.rs
+@@ -0,0 +1,260 @@
++use crate::sys::time::TimeSpec;
++#[cfg(any(
++    target_os = "freebsd",
++    target_os = "dragonfly",
++    target_os = "linux",
++    target_os = "android",
++    target_os = "emscripten",
++))]
++use crate::{unistd::Pid, Error};
++use crate::{Errno, Result};
++use libc::{self, clockid_t};
++use std::mem::MaybeUninit;
++
++/// Clock identifier
++///
++/// Newtype pattern around `clockid_t` (which is just alias). It pervents bugs caused by
++/// accidentally passing wrong value.
++#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
++pub struct ClockId(clockid_t);
++
++impl ClockId {
++    /// Creates `ClockId` from raw `clockid_t`
++    pub fn from_raw(clk_id: clockid_t) -> Self {
++        ClockId(clk_id)
++    }
++
++    /// Returns `ClockId` of a `pid` CPU-time clock
++    #[cfg(any(
++        target_os = "freebsd",
++        target_os = "dragonfly",
++        target_os = "linux",
++        target_os = "android",
++        target_os = "emscripten",
++    ))]
++    pub fn pid_cpu_clock_id(pid: Pid) -> Result<Self> {
++        clock_getcpuclockid(pid)
++    }
++
++    /// Returns resolution of the clock id
++    #[cfg(not(target_os = "redox"))]
++    pub fn res(self) -> Result<TimeSpec> {
++        clock_getres(self)
++    }
++
++    /// Returns the current time on the clock id
++    pub fn now(self) -> Result<TimeSpec> {
++        clock_gettime(self)
++    }
++
++    /// Sets time to `timespec` on the clock id
++    #[cfg(not(any(
++        target_os = "macos",
++        target_os = "ios",
++        all(
++            not(any(target_env = "uclibc", target_env = "newlibc")),
++            any(target_os = "redox", target_os = "hermit",),
++        ),
++    )))]
++    pub fn set_time(self, timespec: TimeSpec) -> Result<()> {
++        clock_settime(self, timespec)
++    }
++
++    /// Gets the raw `clockid_t` wrapped by `self`
++    pub fn as_raw(self) -> clockid_t {
++        self.0
++    }
++
++    #[cfg(any(
++        target_os = "fuchsia",
++        all(
++            not(any(target_env = "uclibc", target_env = "newlib")),
++            any(target_os = "linux", target_os = "android", target_os = "emscripten"),
++        )
++    ))]
++    pub const CLOCK_BOOTTIME: ClockId = ClockId(libc::CLOCK_BOOTTIME);
++    #[cfg(any(
++        target_os = "fuchsia",
++        all(
++            not(any(target_env = "uclibc", target_env = "newlib")),
++            any(target_os = "linux", target_os = "android", target_os = "emscripten")
++        )
++    ))]
++    pub const CLOCK_BOOTTIME_ALARM: ClockId = ClockId(libc::CLOCK_BOOTTIME_ALARM);
++    pub const CLOCK_MONOTONIC: ClockId = ClockId(libc::CLOCK_MONOTONIC);
++    #[cfg(any(
++        target_os = "fuchsia",
++        all(
++            not(any(target_env = "uclibc", target_env = "newlib")),
++            any(target_os = "linux", target_os = "android", target_os = "emscripten")
++        )
++    ))]
++    pub const CLOCK_MONOTONIC_COARSE: ClockId = ClockId(libc::CLOCK_MONOTONIC_COARSE);
++    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++    pub const CLOCK_MONOTONIC_FAST: ClockId = ClockId(libc::CLOCK_MONOTONIC_FAST);
++    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++    pub const CLOCK_MONOTONIC_PRECISE: ClockId = ClockId(libc::CLOCK_MONOTONIC_PRECISE);
++    #[cfg(any(
++        target_os = "fuchsia",
++        all(
++            not(any(target_env = "uclibc", target_env = "newlib")),
++            any(target_os = "linux", target_os = "android", target_os = "emscripten")
++        )
++    ))]
++    pub const CLOCK_MONOTONIC_RAW: ClockId = ClockId(libc::CLOCK_MONOTONIC_RAW);
++    #[cfg(any(
++        target_os = "fuchsia",
++        target_env = "uclibc",
++        target_os = "macos",
++        target_os = "ios",
++        target_os = "freebsd",
++        target_os = "dragonfly",
++        all(
++            not(target_env = "newlib"),
++            any(target_os = "linux", target_os = "android", target_os = "emscripten")
++        )
++    ))]
++    pub const CLOCK_PROCESS_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_PROCESS_CPUTIME_ID);
++    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++    pub const CLOCK_PROF: ClockId = ClockId(libc::CLOCK_PROF);
++    pub const CLOCK_REALTIME: ClockId = ClockId(libc::CLOCK_REALTIME);
++    #[cfg(any(
++        target_os = "fuchsia",
++        all(
++            not(any(target_env = "uclibc", target_env = "newlib")),
++            any(target_os = "linux", target_os = "android", target_os = "emscripten")
++        )
++    ))]
++    pub const CLOCK_REALTIME_ALARM: ClockId = ClockId(libc::CLOCK_REALTIME_ALARM);
++    #[cfg(any(
++        target_os = "fuchsia",
++        all(
++            not(any(target_env = "uclibc", target_env = "newlib")),
++            any(target_os = "linux", target_os = "android", target_os = "emscripten")
++        )
++    ))]
++    pub const CLOCK_REALTIME_COARSE: ClockId = ClockId(libc::CLOCK_REALTIME_COARSE);
++    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++    pub const CLOCK_REALTIME_FAST: ClockId = ClockId(libc::CLOCK_REALTIME_FAST);
++    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++    pub const CLOCK_REALTIME_PRECISE: ClockId = ClockId(libc::CLOCK_REALTIME_PRECISE);
++    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++    pub const CLOCK_SECOND: ClockId = ClockId(libc::CLOCK_SECOND);
++    #[cfg(any(
++        target_os = "fuchsia",
++        all(
++            not(any(target_env = "uclibc", target_env = "newlib")),
++            any(
++                target_os = "emscripten",
++                all(target_os = "linux", target_env = "musl")
++            )
++        )
++    ))]
++    pub const CLOCK_SGI_CYCLE: ClockId = ClockId(libc::CLOCK_SGI_CYCLE);
++    #[cfg(any(
++        target_os = "fuchsia",
++        all(
++            not(any(target_env = "uclibc", target_env = "newlib")),
++            any(
++                target_os = "emscripten",
++                all(target_os = "linux", target_env = "musl")
++            )
++        )
++    ))]
++    pub const CLOCK_TAI: ClockId = ClockId(libc::CLOCK_TAI);
++    #[cfg(any(
++        target_env = "uclibc",
++        target_os = "fuchsia",
++        target_os = "ios",
++        target_os = "macos",
++        target_os = "freebsd",
++        target_os = "dragonfly",
++        all(
++            not(target_env = "newlib"),
++            any(target_os = "linux", target_os = "android", target_os = "emscripten",),
++        ),
++    ))]
++    pub const CLOCK_THREAD_CPUTIME_ID: ClockId = ClockId(libc::CLOCK_THREAD_CPUTIME_ID);
++    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++    pub const CLOCK_UPTIME: ClockId = ClockId(libc::CLOCK_UPTIME);
++    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++    pub const CLOCK_UPTIME_FAST: ClockId = ClockId(libc::CLOCK_UPTIME_FAST);
++    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++    pub const CLOCK_UPTIME_PRECISE: ClockId = ClockId(libc::CLOCK_UPTIME_PRECISE);
++    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++    pub const CLOCK_VIRTUAL: ClockId = ClockId(libc::CLOCK_VIRTUAL);
++}
++
++impl Into<clockid_t> for ClockId {
++    fn into(self) -> clockid_t {
++        self.as_raw()
++    }
++}
++
++impl From<clockid_t> for ClockId {
++    fn from(clk_id: clockid_t) -> Self {
++        ClockId::from_raw(clk_id)
++    }
++}
++
++impl std::fmt::Display for ClockId {
++    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
++        std::fmt::Display::fmt(&self.0, f)
++    }
++}
++
++/// 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()) };
++    Errno::result(ret)?;
++    let res = unsafe { c_time.assume_init() };
++    Ok(TimeSpec::from(res))
++}
++
++/// Get the time of the specified clock, (see
++/// [clock_gettime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_gettime.html)).
++pub fn clock_gettime(clock_id: ClockId) -> Result<TimeSpec> {
++    let mut c_time: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
++    let ret = unsafe { libc::clock_gettime(clock_id.as_raw(), c_time.as_mut_ptr()) };
++    Errno::result(ret)?;
++    let res = unsafe { c_time.assume_init() };
++    Ok(TimeSpec::from(res))
++}
++
++/// Set the time of the specified clock, (see
++/// [clock_settime(2)](https://pubs.opengroup.org/onlinepubs/7908799/xsh/clock_settime.html)).
++#[cfg(not(any(
++    target_os = "macos",
++    target_os = "ios",
++    all(
++        not(any(target_env = "uclibc", target_env = "newlibc")),
++        any(target_os = "redox", target_os = "hermit",),
++    ),
++)))]
++pub fn clock_settime(clock_id: ClockId, timespec: TimeSpec) -> Result<()> {
++    let ret = unsafe { libc::clock_settime(clock_id.as_raw(), timespec.as_ref()) };
++    Errno::result(ret).map(drop)
++}
++
++/// Get the clock id of the specified process id, (see
++/// [clock_getcpuclockid(3)](https://pubs.opengroup.org/onlinepubs/009695399/functions/clock_getcpuclockid.html)).
++#[cfg(any(
++    target_os = "freebsd",
++    target_os = "dragonfly",
++    target_os = "linux",
++    target_os = "android",
++    target_os = "emscripten",
++))]
++pub fn clock_getcpuclockid(pid: Pid) -> Result<ClockId> {
++    let mut clk_id: MaybeUninit<libc::clockid_t> = MaybeUninit::uninit();
++    let ret = unsafe { libc::clock_getcpuclockid(pid.into(), clk_id.as_mut_ptr()) };
++    if ret == 0 {
++        let res = unsafe { clk_id.assume_init() };
++        Ok(ClockId::from(res))
++    } else {
++        Err(Error::Sys(Errno::from_i32(ret)))
++    }
++}
+diff --git a/third_party/rust/nix/src/ucontext.rs b/third_party/rust/nix/src/ucontext.rs
+index 5e10e7d1f8934..a5b8cc75cb330 100644
+--- a/third_party/rust/nix/src/ucontext.rs
++++ b/third_party/rust/nix/src/ucontext.rs
+@@ -1,10 +1,11 @@
+ use libc;
+ #[cfg(not(target_env = "musl"))]
+-use Result;
++use crate::Result;
++#[cfg(not(target_env = "musl"))]
++use crate::errno::Errno;
+ #[cfg(not(target_env = "musl"))]
+-use errno::Errno;
+ use std::mem;
+-use sys::signal::SigSet;
++use crate::sys::signal::SigSet;
+ 
+ #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+ pub struct UContext {
+@@ -14,11 +15,11 @@ pub struct UContext {
+ impl UContext {
+     #[cfg(not(target_env = "musl"))]
+     pub fn get() -> Result<UContext> {
+-        let mut context: libc::ucontext_t = unsafe { mem::uninitialized() };
+-        let res = unsafe {
+-            libc::getcontext(&mut context as *mut libc::ucontext_t)
+-        };
+-        Errno::result(res).map(|_| UContext { context: context })
++        let mut context = mem::MaybeUninit::<libc::ucontext_t>::uninit();
++        let res = unsafe { libc::getcontext(context.as_mut_ptr()) };
++        Errno::result(res).map(|_| unsafe {
++            UContext { context: context.assume_init()}
++        })
+     }
+ 
+     #[cfg(not(target_env = "musl"))]
+@@ -30,10 +31,14 @@ impl UContext {
+     }
+ 
+     pub fn sigmask_mut(&mut self) -> &mut SigSet {
+-        unsafe { mem::transmute(&mut self.context.uc_sigmask) }
++        unsafe {
++            &mut *(&mut self.context.uc_sigmask as *mut libc::sigset_t as *mut SigSet)
++        }
+     }
+ 
+     pub fn sigmask(&self) -> &SigSet {
+-        unsafe { mem::transmute(&self.context.uc_sigmask) }
++        unsafe {
++            &*(&self.context.uc_sigmask as *const libc::sigset_t as *const SigSet)
++        }
+     }
+ }
+diff --git a/third_party/rust/nix/src/unistd.rs b/third_party/rust/nix/src/unistd.rs
+index f422f09198655..59cb1ed8b5901 100644
+--- a/third_party/rust/nix/src/unistd.rs
++++ b/third_party/rust/nix/src/unistd.rs
+@@ -1,18 +1,26 @@
+ //! Safe wrappers around functions found in libc "unistd.h" header
+ 
+-use errno::{self, Errno};
+-use {Error, Result, NixPath};
+-use fcntl::{AtFlags, at_rawfd, fcntl, FdFlag, OFlag};
+-use fcntl::FcntlArg::F_SETFD;
++#[cfg(not(target_os = "redox"))]
++use cfg_if::cfg_if;
++use crate::errno::{self, Errno};
++use crate::{Error, Result, NixPath};
++#[cfg(not(target_os = "redox"))]
++use crate::fcntl::{AtFlags, at_rawfd};
++use crate::fcntl::{FdFlag, OFlag, fcntl};
++use crate::fcntl::FcntlArg::F_SETFD;
+ use libc::{self, c_char, c_void, c_int, c_long, c_uint, size_t, pid_t, off_t,
+-           uid_t, gid_t, mode_t};
++           uid_t, gid_t, mode_t, PATH_MAX};
+ use std::{fmt, mem, ptr};
+-use std::ffi::{CString, CStr, OsString, OsStr};
+-use std::os::unix::ffi::{OsStringExt, OsStrExt};
++use std::convert::Infallible;
++use std::ffi::{CStr, OsString};
++#[cfg(not(target_os = "redox"))]
++use std::ffi::{CString, OsStr};
++use std::os::unix::ffi::OsStringExt;
++#[cfg(not(target_os = "redox"))]
++use std::os::unix::ffi::OsStrExt;
+ use std::os::unix::io::RawFd;
+ use std::path::PathBuf;
+-use void::Void;
+-use sys::stat::Mode;
++use crate::sys::stat::Mode;
+ 
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ pub use self::pivot_root::*;
+@@ -45,12 +53,12 @@ impl Uid {
+     }
+ 
+     /// Returns true if the `Uid` represents privileged user - root. (If it equals zero.)
+-    pub fn is_root(&self) -> bool {
+-        *self == ROOT
++    pub fn is_root(self) -> bool {
++        self == ROOT
+     }
+ 
+     /// Get the raw `uid_t` wrapped by `self`.
+-    pub fn as_raw(&self) -> uid_t {
++    pub fn as_raw(self) -> uid_t {
+         self.0
+     }
+ }
+@@ -88,13 +96,13 @@ impl Gid {
+         getgid()
+     }
+ 
+-    /// Returns effective Gid of calling process. This is practically a more Rusty alias for `getgid`.
++    /// Returns effective Gid of calling process. This is practically a more Rusty alias for `getegid`.
+     pub fn effective() -> Self {
+         getegid()
+     }
+ 
+     /// Get the raw `gid_t` wrapped by `self`.
+-    pub fn as_raw(&self) -> gid_t {
++    pub fn as_raw(self) -> gid_t {
+         self.0
+     }
+ }
+@@ -115,7 +123,7 @@ impl fmt::Display for Gid {
+ ///
+ /// Newtype pattern around `pid_t` (which is just alias). It prevents bugs caused by accidentally
+ /// passing wrong value.
+-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
++#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
+ pub struct Pid(pid_t);
+ 
+ impl Pid {
+@@ -135,7 +143,7 @@ impl Pid {
+     }
+ 
+     /// Get the raw `pid_t` wrapped by `self`.
+-    pub fn as_raw(&self) -> pid_t {
++    pub fn as_raw(self) -> pid_t {
+         self.0
+     }
+ }
+@@ -168,8 +176,8 @@ impl ForkResult {
+ 
+     /// Return `true` if this is the child process of the `fork()`
+     #[inline]
+-    pub fn is_child(&self) -> bool {
+-        match *self {
++    pub fn is_child(self) -> bool {
++        match self {
+             ForkResult::Child => true,
+             _ => false
+         }
+@@ -177,7 +185,7 @@ impl ForkResult {
+ 
+     /// Returns `true` if this is the parent process of the `fork()`
+     #[inline]
+-    pub fn is_parent(&self) -> bool {
++    pub fn is_parent(self) -> bool {
+         !self.is_child()
+     }
+ }
+@@ -192,7 +200,7 @@ impl ForkResult {
+ /// ```no_run
+ /// use nix::unistd::{fork, ForkResult};
+ ///
+-/// match fork() {
++/// match unsafe{fork()} {
+ ///    Ok(ForkResult::Parent { child, .. }) => {
+ ///        println!("Continuing execution in parent process, new child has pid: {}", child);
+ ///    }
+@@ -222,9 +230,9 @@ impl ForkResult {
+ ///
+ /// [async-signal-safe]: http://man7.org/linux/man-pages/man7/signal-safety.7.html
+ #[inline]
+-pub fn fork() -> Result<ForkResult> {
++pub unsafe fn fork() -> Result<ForkResult> {
+     use self::ForkResult::*;
+-    let res = unsafe { libc::fork() };
++    let res = libc::fork();
+ 
+     Errno::result(res).map(|res| match res {
+         0 => Child,
+@@ -285,6 +293,7 @@ pub fn setsid() -> Result<Pid> {
+ /// Obtain the process group ID of the process that is the session leader of the process specified
+ /// by pid. If pid is zero, it specifies the calling process.
+ #[inline]
++#[cfg(not(target_os = "redox"))]
+ pub fn getsid(pid: Option<Pid>) -> Result<Pid> {
+     let res = unsafe { libc::getsid(pid.unwrap_or(Pid(0)).into()) };
+     Errno::result(res).map(Pid)
+@@ -417,6 +426,7 @@ pub fn chdir<P: ?Sized + NixPath>(path: &P) -> Result<()> {
+ /// 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) };
+ 
+@@ -436,9 +446,6 @@ pub fn fchdir(dirfd: RawFd) -> Result<()> {
+ /// # Example
+ ///
+ /// ```rust
+-/// extern crate tempfile;
+-/// extern crate nix;
+-///
+ /// use nix::unistd;
+ /// use nix::sys::stat;
+ /// use tempfile::tempdir;
+@@ -479,9 +486,6 @@ pub fn mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
+ /// # Example
+ ///
+ /// ```rust
+-/// extern crate tempfile;
+-/// extern crate nix;
+-///
+ /// use nix::unistd;
+ /// use nix::sys::stat;
+ /// use tempfile::tempdir;
+@@ -498,6 +502,7 @@ pub fn mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
+ /// }
+ /// ```
+ #[inline]
++#[cfg(not(target_os = "redox"))] // RedoxFS does not support fifo yet
+ pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
+     let res = path.with_nix_path(|cstr| {
+         unsafe { libc::mkfifo(cstr.as_ptr(), mode.bits() as mode_t) }
+@@ -506,6 +511,28 @@ pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
+     Errno::result(res).map(drop)
+ }
+ 
++/// Creates new fifo special file (named pipe) with path `path` and access rights `mode`.
++///
++/// If `dirfd` has a value, then `path` is relative to directory associated with the file descriptor.
++///
++/// If `dirfd` is `None`, then `path` is relative to the current working directory.
++///
++/// # References
++///
++/// [mkfifoat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifoat.html).
++// mkfifoat is not implemented in OSX or android
++#[inline]
++#[cfg(not(any(
++    target_os = "macos", target_os = "ios",
++    target_os = "android", target_os = "redox")))]
++pub fn mkfifoat<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P, mode: Mode) -> Result<()> {
++    let res = path.with_nix_path(|cstr| unsafe {
++        libc::mkfifoat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits() as mode_t)
++    })?;
++
++    Errno::result(res).map(drop)
++}
++
+ /// Creates a symbolic link at `path2` which points to `path1`.
+ ///
+ /// If `dirfd` has a value, then `path2` is relative to directory associated
+@@ -515,6 +542,7 @@ pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
+ /// directory. This is identical to `libc::symlink(path1, path2)`.
+ ///
+ /// See also [symlinkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html).
++#[cfg(not(target_os = "redox"))]
+ pub fn symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
+     path1: &P1,
+     dirfd: Option<RawFd>,
+@@ -534,6 +562,21 @@ pub fn symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
+     Errno::result(res).map(drop)
+ }
+ 
++// Double the buffer capacity up to limit. In case it already has
++// reached the limit, return Errno::ERANGE.
++fn reserve_double_buffer_size<T>(buf: &mut Vec<T>, limit: usize) -> Result<()> {
++    use std::cmp::min;
++
++    if buf.capacity() >= limit {
++        return Err(Error::Sys(Errno::ERANGE))
++    }
++
++    let capacity = min(buf.capacity() * 2, limit);
++    buf.reserve(capacity);
++
++    Ok(())
++}
++
+ /// Returns the current directory as a `PathBuf`
+ ///
+ /// Err is returned if the current user doesn't have the permission to read or search a component
+@@ -542,8 +585,6 @@ pub fn symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
+ /// # Example
+ ///
+ /// ```rust
+-/// extern crate nix;
+-///
+ /// use nix::unistd;
+ ///
+ /// fn main() {
+@@ -576,11 +617,8 @@ pub fn getcwd() -> Result<PathBuf> {
+                 }
+             }
+ 
+-            // Trigger the internal buffer resizing logic of `Vec` by requiring
+-            // more space than the current capacity.
+-            let cap = buf.capacity();
+-            buf.set_len(cap);
+-            buf.reserve(1);
++            // Trigger the internal buffer resizing logic.
++            reserve_double_buffer_size(&mut buf, PATH_MAX as usize)?;
+         }
+     }
+ }
+@@ -590,8 +628,10 @@ fn chown_raw_ids(owner: Option<Uid>, group: Option<Gid>) -> (libc::uid_t, libc::
+     // According to the POSIX specification, -1 is used to indicate that owner and group
+     // are not to be changed.  Since uid_t and gid_t are unsigned types, we have to wrap
+     // around to get -1.
+-    let uid = owner.map(Into::into).unwrap_or((0 as uid_t).wrapping_sub(1));
+-    let gid = group.map(Into::into).unwrap_or((0 as gid_t).wrapping_sub(1));
++    let uid = owner.map(Into::into)
++        .unwrap_or_else(|| (0 as uid_t).wrapping_sub(1));
++    let gid = group.map(Into::into)
++        .unwrap_or_else(|| (0 as gid_t).wrapping_sub(1));
+     (uid, gid)
+ }
+ 
+@@ -612,6 +652,20 @@ pub fn chown<P: ?Sized + NixPath>(path: &P, owner: Option<Uid>, group: Option<Gi
+     Errno::result(res).map(drop)
+ }
+ 
++/// Change the ownership of the file referred to by the open file descriptor `fd` to be owned by
++/// the specified `owner` (user) and `group` (see
++/// [fchown(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchown.html)).
++///
++/// The owner/group for the provided file will not be modified if `None` is
++/// provided for that argument.  Ownership change will be attempted for the path
++/// only if `Some` owner/group is provided.
++#[inline]
++pub fn fchown(fd: RawFd, owner: Option<Uid>, group: Option<Gid>) -> Result<()> {
++    let (uid, gid) = chown_raw_ids(owner, group);
++    let res = unsafe { libc::fchown(fd, uid, gid) };
++    Errno::result(res).map(drop)
++}
++
+ /// Flags for `fchownat` function.
+ #[derive(Clone, Copy, Debug)]
+ pub enum FchownatFlags {
+@@ -640,6 +694,7 @@ pub enum FchownatFlags {
+ /// # References
+ ///
+ /// [fchownat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchownat.html).
++#[cfg(not(target_os = "redox"))]
+ pub fn fchownat<P: ?Sized + NixPath>(
+     dirfd: Option<RawFd>,
+     path: &P,
+@@ -661,10 +716,9 @@ pub fn fchownat<P: ?Sized + NixPath>(
+     Errno::result(res).map(drop)
+ }
+ 
+-fn to_exec_array(args: &[CString]) -> Vec<*const c_char> {
+-    let mut args_p: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect();
+-    args_p.push(ptr::null());
+-    args_p
++fn to_exec_array<S: AsRef<CStr>>(args: &[S]) -> Vec<*const c_char> {
++    use std::iter::once;
++    args.iter().map(|s| s.as_ref().as_ptr()).chain(once(ptr::null())).collect()
+ }
+ 
+ /// Replace the current process image with a new one (see
+@@ -674,7 +728,7 @@ fn to_exec_array(args: &[CString]) -> Vec<*const c_char> {
+ /// performs the same action but does not allow for customization of the
+ /// environment for the new process.
+ #[inline]
+-pub fn execv(path: &CString, argv: &[CString]) -> Result<Void> {
++pub fn execv<S: AsRef<CStr>>(path: &CStr, argv: &[S]) -> Result<Infallible> {
+     let args_p = to_exec_array(argv);
+ 
+     unsafe {
+@@ -698,7 +752,7 @@ pub fn execv(path: &CString, argv: &[CString]) -> Result<Void> {
+ /// in the `args` list is an argument to the new process. Each element in the
+ /// `env` list should be a string in the form "key=value".
+ #[inline]
+-pub fn execve(path: &CString, args: &[CString], env: &[CString]) -> Result<Void> {
++pub fn execve<SA: AsRef<CStr>, SE: AsRef<CStr>>(path: &CStr, args: &[SA], env: &[SE]) -> Result<Infallible> {
+     let args_p = to_exec_array(args);
+     let env_p = to_exec_array(env);
+ 
+@@ -719,7 +773,7 @@ pub fn execve(path: &CString, args: &[CString], env: &[CString]) -> Result<Void>
+ /// would not work if "bash" was specified for the path argument, but `execvp`
+ /// would assuming that a bash executable was on the system `PATH`.
+ #[inline]
+-pub fn execvp(filename: &CString, args: &[CString]) -> Result<Void> {
++pub fn execvp<S: AsRef<CStr>>(filename: &CStr, args: &[S]) -> Result<Infallible> {
+     let args_p = to_exec_array(args);
+ 
+     unsafe {
+@@ -739,7 +793,7 @@ pub fn execvp(filename: &CString, args: &[CString]) -> Result<Void> {
+ #[cfg(any(target_os = "haiku",
+           target_os = "linux",
+           target_os = "openbsd"))]
+-pub fn execvpe(filename: &CString, args: &[CString], env: &[CString]) -> Result<Void> {
++pub fn execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>(filename: &CStr, args: &[SA], env: &[SE]) -> Result<Infallible> {
+     let args_p = to_exec_array(args);
+     let env_p = to_exec_array(env);
+ 
+@@ -767,7 +821,7 @@ pub fn execvpe(filename: &CString, args: &[CString], env: &[CString]) -> Result<
+           target_os = "linux",
+           target_os = "freebsd"))]
+ #[inline]
+-pub fn fexecve(fd: RawFd, args: &[CString], env: &[CString]) -> Result<Void> {
++pub fn fexecve<SA: AsRef<CStr> ,SE: AsRef<CStr>>(fd: RawFd, args: &[SA], env: &[SE]) -> Result<Infallible> {
+     let args_p = to_exec_array(args);
+     let env_p = to_exec_array(env);
+ 
+@@ -790,8 +844,8 @@ pub fn fexecve(fd: RawFd, args: &[CString], env: &[CString]) -> Result<Void> {
+ /// is referenced as a file descriptor to the base directory plus a path.
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ #[inline]
+-pub fn execveat(dirfd: RawFd, pathname: &CString, args: &[CString],
+-                env: &[CString], flags: super::fcntl::AtFlags) -> Result<Void> {
++pub fn execveat<SA: AsRef<CStr>,SE: AsRef<CStr>>(dirfd: RawFd, pathname: &CStr, args: &[SA],
++                env: &[SE], flags: super::fcntl::AtFlags) -> Result<Infallible> {
+     let args_p = to_exec_array(args);
+     let env_p = to_exec_array(env);
+ 
+@@ -828,11 +882,12 @@ pub fn execveat(dirfd: RawFd, pathname: &CString, args: &[CString],
+ ///   descriptors will remain identical after daemonizing.
+ /// * `noclose = false`: The process' stdin, stdout, and stderr will point to
+ ///   `/dev/null` after daemonizing.
+-#[cfg_attr(any(target_os = "macos", target_os = "ios"), deprecated(
+-    since="0.14.0",
+-    note="Deprecated in MacOSX 10.5"
+-))]
+-#[cfg_attr(any(target_os = "macos", target_os = "ios"), allow(deprecated))]
++#[cfg(any(target_os = "android",
++          target_os = "dragonfly",
++          target_os = "freebsd",
++          target_os = "linux",
++          target_os = "netbsd",
++          target_os = "openbsd"))]
+ pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> {
+     let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) };
+     Errno::result(res).map(drop)
+@@ -845,6 +900,7 @@ pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> {
+ /// On some systems, the host name is limited to as few as 64 bytes.  An error
+ /// will be return if the name is not valid or the current process does not have
+ /// permissions to update the host name.
++#[cfg(not(target_os = "redox"))]
+ pub fn sethostname<S: AsRef<OsStr>>(name: S) -> Result<()> {
+     // Handle some differences in type of the len arg across platforms.
+     cfg_if! {
+@@ -906,9 +962,6 @@ pub fn gethostname(buffer: &mut [u8]) -> Result<&CStr> {
+ /// # Examples
+ ///
+ /// ```no_run
+-/// extern crate tempfile;
+-/// extern crate nix;
+-///
+ /// use std::os::unix::io::AsRawFd;
+ /// use nix::unistd::close;
+ ///
+@@ -919,9 +972,6 @@ pub fn gethostname(buffer: &mut [u8]) -> Result<&CStr> {
+ /// ```
+ ///
+ /// ```rust
+-/// extern crate tempfile;
+-/// extern crate nix;
+-///
+ /// use std::os::unix::io::IntoRawFd;
+ /// use nix::unistd::close;
+ ///
+@@ -969,20 +1019,14 @@ pub enum Whence {
+     /// Specify an offset relative to the next location in the file greater than or
+     /// equal to offset that contains some data. If offset points to
+     /// some data, then the file offset is set to offset.
+-    #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
+-          all(target_os = "linux", not(any(target_env = "musl",
+-                                           target_arch = "mips",
+-                                           target_arch = "mips64")))))]
++    #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
+     SeekData = libc::SEEK_DATA,
+     /// Specify an offset relative to the next hole in the file greater than
+     /// or equal to offset. If offset points into the middle of a hole, then
+     /// the file offset should be set to offset. If there is no hole past offset,
+     /// then the file offset should be adjusted to the end of the file (i.e., there
+     /// is an implicit hole at the end of any file).
+-    #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
+-          all(target_os = "linux", not(any(target_env = "musl",
+-                                           target_arch = "mips",
+-                                           target_arch = "mips64")))))]
++    #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux"))]
+     SeekHole = libc::SEEK_HOLE
+ }
+ 
+@@ -1007,13 +1051,13 @@ pub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result<libc:
+ /// See also [pipe(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html)
+ pub fn pipe() -> Result<(RawFd, RawFd)> {
+     unsafe {
+-        let mut fds: [c_int; 2] = mem::uninitialized();
++        let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit();
+ 
+-        let res = libc::pipe(fds.as_mut_ptr());
++        let res = libc::pipe(fds.as_mut_ptr() as *mut c_int);
+ 
+         Errno::result(res)?;
+ 
+-        Ok((fds[0], fds[1]))
++        Ok((fds.assume_init()[0], fds.assume_init()[1]))
+     }
+ }
+ 
+@@ -1022,7 +1066,9 @@ pub fn pipe() -> Result<(RawFd, RawFd)> {
+ /// The following flags are supported, and will be set atomically as the pipe is
+ /// created:
+ ///
+-/// `O_CLOEXEC`:    Set the close-on-exec flag for the new file descriptors.
++/// `O_CLOEXEC`:    Set the close-on-exec flag for the new file descriptors.  
++#[cfg_attr(target_os = "linux", doc = "`O_DIRECT`: Create a pipe that performs I/O in \"packet\" mode.  ")]
++#[cfg_attr(target_os = "netbsd", doc = "`O_NOSIGPIPE`: Return `EPIPE` instead of raising `SIGPIPE`.  ")]
+ /// `O_NONBLOCK`:   Set the non-blocking flag for the ends of the pipe.
+ ///
+ /// See also [pipe(2)](http://man7.org/linux/man-pages/man2/pipe.2.html)
+@@ -1031,74 +1077,26 @@ pub fn pipe() -> Result<(RawFd, RawFd)> {
+           target_os = "emscripten",
+           target_os = "freebsd",
+           target_os = "linux",
++          target_os = "redox",
+           target_os = "netbsd",
+           target_os = "openbsd"))]
+ pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
+-    let mut fds: [c_int; 2] = unsafe { mem::uninitialized() };
+-
+-    let res = unsafe { libc::pipe2(fds.as_mut_ptr(), flags.bits()) };
+-
+-    Errno::result(res)?;
+-
+-    Ok((fds[0], fds[1]))
+-}
++    let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit();
+ 
+-/// Like `pipe`, but allows setting certain file descriptor flags.
+-///
+-/// The following flags are supported, and will be set after the pipe is
+-/// created:
+-///
+-/// `O_CLOEXEC`:    Set the close-on-exec flag for the new file descriptors.
+-/// `O_NONBLOCK`:   Set the non-blocking flag for the ends of the pipe.
+-#[cfg(any(target_os = "ios", target_os = "macos"))]
+-#[deprecated(
+-    since="0.10.0",
+-    note="pipe2(2) is not actually atomic on these platforms.  Use pipe(2) and fcntl(2) instead"
+-)]
+-pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
+-    let mut fds: [c_int; 2] = unsafe { mem::uninitialized() };
+-
+-    let res = unsafe { libc::pipe(fds.as_mut_ptr()) };
++    let res = unsafe {
++        libc::pipe2(fds.as_mut_ptr() as *mut c_int, flags.bits())
++    };
+ 
+     Errno::result(res)?;
+ 
+-    pipe2_setflags(fds[0], fds[1], flags)?;
+-
+-    Ok((fds[0], fds[1]))
+-}
+-
+-#[cfg(any(target_os = "ios", target_os = "macos"))]
+-fn pipe2_setflags(fd1: RawFd, fd2: RawFd, flags: OFlag) -> Result<()> {
+-    use fcntl::FcntlArg::F_SETFL;
+-
+-    let mut res = Ok(0);
+-
+-    if flags.contains(OFlag::O_CLOEXEC) {
+-        res = res
+-            .and_then(|_| fcntl(fd1, F_SETFD(FdFlag::FD_CLOEXEC)))
+-            .and_then(|_| fcntl(fd2, F_SETFD(FdFlag::FD_CLOEXEC)));
+-    }
+-
+-    if flags.contains(OFlag::O_NONBLOCK) {
+-        res = res
+-            .and_then(|_| fcntl(fd1, F_SETFL(OFlag::O_NONBLOCK)))
+-            .and_then(|_| fcntl(fd2, F_SETFL(OFlag::O_NONBLOCK)));
+-    }
+-
+-    match res {
+-        Ok(_) => Ok(()),
+-        Err(e) => {
+-            let _ = close(fd1);
+-            let _ = close(fd2);
+-            Err(e)
+-        }
+-    }
++    unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) }
+ }
+ 
+ /// Truncate a file to a specified length
+ ///
+ /// See also
+ /// [truncate(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html)
++#[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 {
+@@ -1132,6 +1130,59 @@ pub fn isatty(fd: RawFd) -> Result<bool> {
+     }
+ }
+ 
++/// Flags for `linkat` function.
++#[derive(Clone, Copy, Debug)]
++pub enum LinkatFlags {
++    SymlinkFollow,
++    NoSymlinkFollow,
++}
++
++/// Link one file to another file
++///
++/// Creates a new link (directory entry) at `newpath` for the existing file at `oldpath`. In the
++/// case of a relative `oldpath`, the path is interpreted relative to the directory associated
++/// with file descriptor `olddirfd` instead of the current working directory and similiarly for
++/// `newpath` and file descriptor `newdirfd`. In case `flag` is LinkatFlags::SymlinkFollow and
++/// `oldpath` names a symoblic link, a new link for the target of the symbolic link is created.
++/// If either `olddirfd` or `newdirfd` is `None`, `AT_FDCWD` is used respectively where `oldpath`
++/// and/or `newpath` is then interpreted relative to the current working directory of the calling
++/// process. If either `oldpath` or `newpath` is absolute, then `dirfd` is ignored.
++///
++/// # References
++/// See also [linkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/linkat.html)
++#[cfg(not(target_os = "redox"))] // RedoxFS does not support symlinks yet
++pub fn linkat<P: ?Sized + NixPath>(
++    olddirfd: Option<RawFd>,
++    oldpath: &P,
++    newdirfd: Option<RawFd>,
++    newpath: &P,
++    flag: LinkatFlags,
++) -> Result<()> {
++
++    let atflag =
++        match flag {
++            LinkatFlags::SymlinkFollow => AtFlags::AT_SYMLINK_FOLLOW,
++            LinkatFlags::NoSymlinkFollow => AtFlags::empty(),
++        };
++
++    let res =
++        oldpath.with_nix_path(|oldcstr| {
++            newpath.with_nix_path(|newcstr| {
++            unsafe {
++                libc::linkat(
++                    at_rawfd(olddirfd),
++                    oldcstr.as_ptr(),
++                    at_rawfd(newdirfd),
++                    newcstr.as_ptr(),
++                    atflag.bits() as libc::c_int
++                    )
++                }
++            })
++        })??;
++    Errno::result(res).map(drop)
++}
++
++
+ /// Remove a directory entry
+ ///
+ /// See also [unlink(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html)
+@@ -1161,6 +1212,7 @@ pub enum UnlinkatFlags {
+ ///
+ /// # References
+ /// See also [unlinkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/unlinkat.html)
++#[cfg(not(target_os = "redox"))]
+ pub fn unlinkat<P: ?Sized + NixPath>(
+     dirfd: Option<RawFd>,
+     path: &P,
+@@ -1181,6 +1233,7 @@ pub fn unlinkat<P: ?Sized + NixPath>(
+ 
+ 
+ #[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()) }
+@@ -1199,7 +1252,7 @@ pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> {
+     target_os = "netbsd",
+     target_os = "openbsd"
+ ))]
+-pub fn sync() -> () {
++pub fn sync() {
+     unsafe { libc::sync() };
+ }
+ 
+@@ -1309,6 +1362,28 @@ pub fn setgid(gid: Gid) -> Result<()> {
+     Errno::result(res).map(drop)
+ }
+ 
++/// Set the user identity used for filesystem checks per-thread.
++/// On both success and failure, this call returns the previous filesystem user
++/// ID of the caller.
++///
++/// See also [setfsuid(2)](http://man7.org/linux/man-pages/man2/setfsuid.2.html)
++#[cfg(any(target_os = "linux", target_os = "android"))]
++pub fn setfsuid(uid: Uid) -> Uid {
++    let prev_fsuid = unsafe { libc::setfsuid(uid.into()) };
++    Uid::from_raw(prev_fsuid as uid_t)
++}
++
++/// Set the group identity used for filesystem checks per-thread.
++/// On both success and failure, this call returns the previous filesystem group
++/// ID of the caller.
++///
++/// See also [setfsgid(2)](http://man7.org/linux/man-pages/man2/setfsgid.2.html)
++#[cfg(any(target_os = "linux", target_os = "android"))]
++pub fn setfsgid(gid: Gid) -> Gid {
++    let prev_fsgid = unsafe { libc::setfsgid(gid.into()) };
++    Gid::from_raw(prev_fsgid as gid_t)
++}
++
+ /// Get the list of supplementary group IDs of the calling process.
+ ///
+ /// [Further reading](http://pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html)
+@@ -1318,33 +1393,39 @@ pub fn setgid(gid: Gid) -> Result<()> {
+ /// with the `opendirectoryd` service.
+ #[cfg(not(any(target_os = "ios", target_os = "macos")))]
+ pub fn getgroups() -> Result<Vec<Gid>> {
+-    // First get the number of groups so we can size our Vec
+-    let ret = unsafe { libc::getgroups(0, ptr::null_mut()) };
++    // First get the maximum number of groups. The value returned
++    // shall always be greater than or equal to one and less than or
++    // equal to the value of {NGROUPS_MAX} + 1.
++    let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) {
++        Ok(Some(n)) => (n + 1) as usize,
++        Ok(None) | Err(_) => <usize>::max_value(),
++    };
++
++    // Next, get the number of groups so we can size our Vec
++    let ngroups = unsafe { libc::getgroups(0, ptr::null_mut()) };
+ 
+     // Now actually get the groups. We try multiple times in case the number of
+     // groups has changed since the first call to getgroups() and the buffer is
+     // now too small.
+-    let mut groups = Vec::<Gid>::with_capacity(Errno::result(ret)? as usize);
++    let mut groups = Vec::<Gid>::with_capacity(Errno::result(ngroups)? as usize);
+     loop {
+         // FIXME: On the platforms we currently support, the `Gid` struct has
+         // the same representation in memory as a bare `gid_t`. This is not
+         // necessarily the case on all Rust platforms, though. See RFC 1785.
+-        let ret = unsafe {
++        let ngroups = unsafe {
+             libc::getgroups(groups.capacity() as c_int, groups.as_mut_ptr() as *mut gid_t)
+         };
+ 
+-        match Errno::result(ret) {
++        match Errno::result(ngroups) {
+             Ok(s) => {
+                 unsafe { groups.set_len(s as usize) };
+                 return Ok(groups);
+             },
+             Err(Error::Sys(Errno::EINVAL)) => {
+-                // EINVAL indicates that the buffer size was too small. Trigger
+-                // the internal buffer resizing logic of `Vec` by requiring
+-                // more space than the current capacity.
+-                let cap = groups.capacity();
+-                unsafe { groups.set_len(cap) };
+-                groups.reserve(1);
++                // EINVAL indicates that the buffer size was too
++                // small, resize it up to ngroups_max as limit.
++                reserve_double_buffer_size(&mut groups, ngroups_max)
++                    .or(Err(Error::Sys(Errno::EINVAL)))?;
+             },
+             Err(e) => return Err(e)
+         }
+@@ -1380,11 +1461,9 @@ pub fn getgroups() -> Result<Vec<Gid>> {
+ /// #     Ok(())
+ /// # }
+ /// #
+-/// # fn main() {
+-/// #     try_main().unwrap();
+-/// # }
++/// # try_main().unwrap();
+ /// ```
+-#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))]
+ pub fn setgroups(groups: &[Gid]) -> Result<()> {
+     cfg_if! {
+         if #[cfg(any(target_os = "dragonfly",
+@@ -1428,15 +1507,14 @@ pub fn setgroups(groups: &[Gid]) -> Result<()> {
+ /// and `setgroups()`. Additionally, while some implementations will return a
+ /// partial list of groups when `NGROUPS_MAX` is exceeded, this implementation
+ /// will only ever return the complete list or else an error.
+-#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))]
+ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> {
+     let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) {
+         Ok(Some(n)) => n as c_int,
+         Ok(None) | Err(_) => <c_int>::max_value(),
+     };
+     use std::cmp::min;
+-    let mut ngroups = min(ngroups_max, 8);
+-    let mut groups = Vec::<Gid>::with_capacity(ngroups as usize);
++    let mut groups = Vec::<Gid>::with_capacity(min(ngroups_max, 8) as usize);
+     cfg_if! {
+         if #[cfg(any(target_os = "ios", target_os = "macos"))] {
+             type getgrouplist_group_t = c_int;
+@@ -1446,6 +1524,7 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> {
+     }
+     let gid: gid_t = group.into();
+     loop {
++        let mut ngroups = groups.capacity() as i32;
+         let ret = unsafe {
+             libc::getgrouplist(user.as_ptr(),
+                                gid as getgrouplist_group_t,
+@@ -1462,19 +1541,8 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> {
+             // BSD systems will still fill the groups buffer with as many
+             // groups as possible, but Linux manpages do not mention this
+             // behavior.
+-
+-            let cap = groups.capacity();
+-            if cap >= ngroups_max as usize {
+-                // We already have the largest capacity we can, give up
+-                return Err(Error::invalid_argument());
+-            }
+-
+-            // Reserve space for at least ngroups
+-            groups.reserve(ngroups as usize);
+-
+-            // Even if the buffer gets resized to bigger than ngroups_max,
+-            // don't ever ask for more than ngroups_max groups
+-            ngroups = min(ngroups_max, groups.capacity() as c_int);
++            reserve_double_buffer_size(&mut groups, ngroups_max as usize)
++                .or_else(|_| Err(Error::invalid_argument()))?;
+         }
+     }
+ }
+@@ -1515,11 +1583,9 @@ pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> {
+ /// #     Ok(())
+ /// # }
+ /// #
+-/// # fn main() {
+-/// #     try_main().unwrap();
+-/// # }
++/// # try_main().unwrap();
+ /// ```
+-#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))]
+ pub fn initgroups(user: &CStr, group: Gid) -> Result<()> {
+     cfg_if! {
+         if #[cfg(any(target_os = "ios", target_os = "macos"))] {
+@@ -1538,6 +1604,7 @@ pub fn initgroups(user: &CStr, group: Gid) -> Result<()> {
+ ///
+ /// See also [pause(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/pause.html).
+ #[inline]
++#[cfg(not(target_os = "redox"))]
+ pub fn pause() {
+     unsafe { libc::pause() };
+ }
+@@ -1568,7 +1635,8 @@ pub mod alarm {
+     //!
+     //! 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};
+@@ -1577,14 +1645,23 @@ pub mod alarm {
+     //! // 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));
+     //! ```
+@@ -1593,8 +1670,6 @@ pub mod alarm {
+     //!
+     //! See also [alarm(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/alarm.html).
+ 
+-    use libc;
+-
+     /// Schedule an alarm signal.
+     ///
+     /// This will cause the system to generate a `SIGALRM` signal for the
+@@ -1630,10 +1705,10 @@ pub fn sleep(seconds: c_uint) -> c_uint {
+     unsafe { libc::sleep(seconds) }
+ }
+ 
++#[cfg(not(target_os = "redox"))]
+ pub mod acct {
+-    use libc;
+-    use {Result, NixPath};
+-    use errno::Errno;
++    use crate::{Result, NixPath};
++    use crate::errno::Errno;
+     use std::ptr;
+ 
+     /// Enable process accounting
+@@ -1711,7 +1786,7 @@ pub fn mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)> {
+ #[repr(i32)]
+ pub enum PathconfVar {
+     #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "linux",
+-              target_os = "netbsd", target_os = "openbsd"))]
++              target_os = "netbsd", target_os = "openbsd", target_os = "redox"))]
+     /// Minimum number of bits needed to represent, as a signed integer value,
+     /// the maximum size of a regular file allowed in the specified directory.
+     FILESIZEBITS = libc::_PC_FILESIZEBITS,
+@@ -1735,11 +1810,11 @@ pub enum PathconfVar {
+     /// a pipe.
+     PIPE_BUF = libc::_PC_PIPE_BUF,
+     #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "linux",
+-              target_os = "netbsd", target_os = "openbsd"))]
++              target_os = "netbsd", target_os = "openbsd", target_os = "redox"))]
+     /// Symbolic links can be created.
+     POSIX2_SYMLINKS = libc::_PC_2_SYMLINKS,
+     #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
+-              target_os = "linux", target_os = "openbsd"))]
++              target_os = "linux", target_os = "openbsd", target_os = "redox"))]
+     /// Minimum number of bytes of storage actually allocated for any portion of
+     /// a file.
+     POSIX_ALLOC_SIZE_MIN = libc::_PC_ALLOC_SIZE_MIN,
+@@ -1749,19 +1824,20 @@ pub enum PathconfVar {
+     /// `POSIX_REC_MIN_XFER_SIZE` and `POSIX_REC_MAX_XFER_SIZE` values.
+     POSIX_REC_INCR_XFER_SIZE = libc::_PC_REC_INCR_XFER_SIZE,
+     #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
+-              target_os = "linux", target_os = "openbsd"))]
++              target_os = "linux", target_os = "openbsd", target_os = "redox"))]
+     /// Maximum recommended file transfer size.
+     POSIX_REC_MAX_XFER_SIZE = libc::_PC_REC_MAX_XFER_SIZE,
+     #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
+-              target_os = "linux", target_os = "openbsd"))]
++              target_os = "linux", target_os = "openbsd", target_os = "redox"))]
+     /// Minimum recommended file transfer size.
+     POSIX_REC_MIN_XFER_SIZE = libc::_PC_REC_MIN_XFER_SIZE,
+     #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
+-              target_os = "linux", target_os = "openbsd"))]
++              target_os = "linux", target_os = "openbsd", target_os = "redox"))]
+     ///  Recommended file transfer buffer alignment.
+     POSIX_REC_XFER_ALIGN = libc::_PC_REC_XFER_ALIGN,
+     #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
+-              target_os = "linux", target_os = "netbsd", target_os = "openbsd"))]
++              target_os = "linux", target_os = "netbsd", target_os = "openbsd",
++              target_os = "redox"))]
+     /// Maximum number of bytes in a symbolic link.
+     SYMLINK_MAX = libc::_PC_SYMLINK_MAX,
+     /// The use of `chown` and `fchown` is restricted to a process with
+@@ -1775,17 +1851,18 @@ pub enum PathconfVar {
+     /// disable terminal special character handling.
+     _POSIX_VDISABLE = libc::_PC_VDISABLE,
+     #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
+-              target_os = "linux", target_os = "openbsd"))]
++              target_os = "linux", target_os = "openbsd", target_os = "redox"))]
+     /// Asynchronous input or output operations may be performed for the
+     /// associated file.
+     _POSIX_ASYNC_IO = libc::_PC_ASYNC_IO,
+     #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
+-              target_os = "linux", target_os = "openbsd"))]
++              target_os = "linux", target_os = "openbsd", target_os = "redox"))]
+     /// Prioritized input or output operations may be performed for the
+     /// associated file.
+     _POSIX_PRIO_IO = libc::_PC_PRIO_IO,
+     #[cfg(any(target_os = "android", target_os = "dragonfly", target_os = "freebsd",
+-              target_os = "linux", target_os = "netbsd", target_os = "openbsd"))]
++              target_os = "linux", target_os = "netbsd", target_os = "openbsd",
++              target_os = "redox"))]
+     /// Synchronized input or output operations may be performed for the
+     /// associated file.
+     _POSIX_SYNC_IO = libc::_PC_SYNC_IO,
+@@ -1886,9 +1963,11 @@ pub fn pathconf<P: ?Sized + NixPath>(path: &P, var: PathconfVar) -> Result<Optio
+ pub enum SysconfVar {
+     /// Maximum number of I/O operations in a single list I/O call supported by
+     /// the implementation.
++    #[cfg(not(target_os = "redox"))]
+     AIO_LISTIO_MAX = libc::_SC_AIO_LISTIO_MAX,
+     /// Maximum number of outstanding asynchronous I/O operations supported by
+     /// the implementation.
++    #[cfg(not(target_os = "redox"))]
+     AIO_MAX = libc::_SC_AIO_MAX,
+     #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
+               target_os = "ios", target_os="linux", target_os = "macos",
+@@ -1899,25 +1978,34 @@ pub enum SysconfVar {
+     /// Maximum length of argument to the exec functions including environment data.
+     ARG_MAX = libc::_SC_ARG_MAX,
+     /// Maximum number of functions that may be registered with `atexit`.
++    #[cfg(not(target_os = "redox"))]
+     ATEXIT_MAX = libc::_SC_ATEXIT_MAX,
+     /// Maximum obase values allowed by the bc utility.
++    #[cfg(not(target_os = "redox"))]
+     BC_BASE_MAX = libc::_SC_BC_BASE_MAX,
+     /// Maximum number of elements permitted in an array by the bc utility.
++    #[cfg(not(target_os = "redox"))]
+     BC_DIM_MAX = libc::_SC_BC_DIM_MAX,
+     /// Maximum scale value allowed by the bc utility.
++    #[cfg(not(target_os = "redox"))]
+     BC_SCALE_MAX = libc::_SC_BC_SCALE_MAX,
+     /// Maximum length of a string constant accepted by the bc utility.
++    #[cfg(not(target_os = "redox"))]
+     BC_STRING_MAX = libc::_SC_BC_STRING_MAX,
+     /// Maximum number of simultaneous processes per real user ID.
+     CHILD_MAX = libc::_SC_CHILD_MAX,
+-    // _SC_CLK_TCK is obsolete
++    // The number of clock ticks per second.
++    CLK_TCK = libc::_SC_CLK_TCK,
+     /// Maximum number of weights that can be assigned to an entry of the
+     /// LC_COLLATE order keyword in the locale definition file
++    #[cfg(not(target_os = "redox"))]
+     COLL_WEIGHTS_MAX = libc::_SC_COLL_WEIGHTS_MAX,
+     /// Maximum number of timer expiration overruns.
++    #[cfg(not(target_os = "redox"))]
+     DELAYTIMER_MAX = libc::_SC_DELAYTIMER_MAX,
+     /// Maximum number of expressions that can be nested within parentheses by
+     /// the expr utility.
++    #[cfg(not(target_os = "redox"))]
+     EXPR_NEST_MAX = libc::_SC_EXPR_NEST_MAX,
+     #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
+               target_os="linux", target_os = "macos", target_os="netbsd",
+@@ -1927,23 +2015,29 @@ pub enum SysconfVar {
+     HOST_NAME_MAX = libc::_SC_HOST_NAME_MAX,
+     /// Maximum number of iovec structures that one process has available for
+     /// use with `readv` or `writev`.
++    #[cfg(not(target_os = "redox"))]
+     IOV_MAX = libc::_SC_IOV_MAX,
+     /// Unless otherwise noted, the maximum length, in bytes, of a utility's
+     /// input line (either standard input or another file), when the utility is
+     /// described as processing text files. The length includes room for the
+     /// trailing <newline>.
++    #[cfg(not(target_os = "redox"))]
+     LINE_MAX = libc::_SC_LINE_MAX,
+     /// Maximum length of a login name.
+     LOGIN_NAME_MAX = libc::_SC_LOGIN_NAME_MAX,
+     /// Maximum number of simultaneous supplementary group IDs per process.
+     NGROUPS_MAX = libc::_SC_NGROUPS_MAX,
+     /// Initial size of `getgrgid_r` and `getgrnam_r` data buffers
++    #[cfg(not(target_os = "redox"))]
+     GETGR_R_SIZE_MAX = libc::_SC_GETGR_R_SIZE_MAX,
+     /// Initial size of `getpwuid_r` and `getpwnam_r` data buffers
++    #[cfg(not(target_os = "redox"))]
+     GETPW_R_SIZE_MAX = libc::_SC_GETPW_R_SIZE_MAX,
+     /// The maximum number of open message queue descriptors a process may hold.
++    #[cfg(not(target_os = "redox"))]
+     MQ_OPEN_MAX = libc::_SC_MQ_OPEN_MAX,
+     /// The maximum number of message priorities supported by the implementation.
++    #[cfg(not(target_os = "redox"))]
+     MQ_PRIO_MAX = libc::_SC_MQ_PRIO_MAX,
+     /// A value one greater than the maximum value that the system may assign to
+     /// a newly-created file descriptor.
+@@ -1958,6 +2052,7 @@ pub enum SysconfVar {
+     /// The implementation supports barriers.
+     _POSIX_BARRIERS = libc::_SC_BARRIERS,
+     /// The implementation supports asynchronous input and output.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX_ASYNCHRONOUS_IO = libc::_SC_ASYNCHRONOUS_IO,
+     #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
+               target_os="linux", target_os = "macos", target_os="netbsd",
+@@ -1970,24 +2065,32 @@ pub enum SysconfVar {
+     /// The implementation supports the Process CPU-Time Clocks option.
+     _POSIX_CPUTIME = libc::_SC_CPUTIME,
+     /// The implementation supports the File Synchronization option.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX_FSYNC = libc::_SC_FSYNC,
+     #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
+               target_os="linux", target_os = "macos", target_os="openbsd"))]
+     /// The implementation supports the IPv6 option.
+     _POSIX_IPV6 = libc::_SC_IPV6,
+     /// The implementation supports job control.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX_JOB_CONTROL = libc::_SC_JOB_CONTROL,
+     /// The implementation supports memory mapped Files.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX_MAPPED_FILES = libc::_SC_MAPPED_FILES,
+     /// The implementation supports the Process Memory Locking option.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX_MEMLOCK = libc::_SC_MEMLOCK,
+     /// The implementation supports the Range Memory Locking option.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX_MEMLOCK_RANGE = libc::_SC_MEMLOCK_RANGE,
+     /// The implementation supports memory protection.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX_MEMORY_PROTECTION = libc::_SC_MEMORY_PROTECTION,
+     /// The implementation supports the Message Passing option.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX_MESSAGE_PASSING = libc::_SC_MESSAGE_PASSING,
+     /// The implementation supports the Monotonic Clock option.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX_MONOTONIC_CLOCK = libc::_SC_MONOTONIC_CLOCK,
+     #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
+               target_os = "ios", target_os="linux", target_os = "macos",
+@@ -1995,6 +2098,7 @@ pub enum SysconfVar {
+     /// The implementation supports the Prioritized Input and Output option.
+     _POSIX_PRIORITIZED_IO = libc::_SC_PRIORITIZED_IO,
+     /// The implementation supports the Process Scheduling option.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX_PRIORITY_SCHEDULING = libc::_SC_PRIORITY_SCHEDULING,
+     #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
+               target_os="linux", target_os = "macos", target_os="openbsd"))]
+@@ -2016,10 +2120,13 @@ pub enum SysconfVar {
+     /// The implementation supports the Regular Expression Handling option.
+     _POSIX_REGEXP = libc::_SC_REGEXP,
+     /// Each process has a saved set-user-ID and a saved set-group-ID.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX_SAVED_IDS = libc::_SC_SAVED_IDS,
+     /// The implementation supports semaphores.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX_SEMAPHORES = libc::_SC_SEMAPHORES,
+     /// The implementation supports the Shared Memory Objects option.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX_SHARED_MEMORY_OBJECTS = libc::_SC_SHARED_MEMORY_OBJECTS,
+     #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
+               target_os="linux", target_os = "macos", target_os="netbsd",
+@@ -2044,10 +2151,13 @@ pub enum SysconfVar {
+               target_os="openbsd"))]
+     _POSIX_SS_REPL_MAX = libc::_SC_SS_REPL_MAX,
+     /// The implementation supports the Synchronized Input and Output option.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX_SYNCHRONIZED_IO = libc::_SC_SYNCHRONIZED_IO,
+     /// The implementation supports the Thread Stack Address Attribute option.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX_THREAD_ATTR_STACKADDR = libc::_SC_THREAD_ATTR_STACKADDR,
+     /// The implementation supports the Thread Stack Size Attribute option.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX_THREAD_ATTR_STACKSIZE = libc::_SC_THREAD_ATTR_STACKSIZE,
+     #[cfg(any(target_os = "ios", target_os="linux", target_os = "macos",
+               target_os="netbsd", target_os="openbsd"))]
+@@ -2055,10 +2165,13 @@ pub enum SysconfVar {
+     _POSIX_THREAD_CPUTIME = libc::_SC_THREAD_CPUTIME,
+     /// The implementation supports the Non-Robust Mutex Priority Inheritance
+     /// option.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX_THREAD_PRIO_INHERIT = libc::_SC_THREAD_PRIO_INHERIT,
+     /// The implementation supports the Non-Robust Mutex Priority Protection option.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX_THREAD_PRIO_PROTECT = libc::_SC_THREAD_PRIO_PROTECT,
+     /// The implementation supports the Thread Execution Scheduling option.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX_THREAD_PRIORITY_SCHEDULING = libc::_SC_THREAD_PRIORITY_SCHEDULING,
+     #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
+               target_os="linux", target_os = "macos", target_os="netbsd",
+@@ -2073,18 +2186,21 @@ pub enum SysconfVar {
+     /// The implementation supports the Robust Mutex Priority Protection option.
+     _POSIX_THREAD_ROBUST_PRIO_PROTECT = libc::_SC_THREAD_ROBUST_PRIO_PROTECT,
+     /// The implementation supports thread-safe functions.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX_THREAD_SAFE_FUNCTIONS = libc::_SC_THREAD_SAFE_FUNCTIONS,
+     #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
+               target_os="linux", target_os = "macos", target_os="openbsd"))]
+     /// The implementation supports the Thread Sporadic Server option.
+     _POSIX_THREAD_SPORADIC_SERVER = libc::_SC_THREAD_SPORADIC_SERVER,
+     /// The implementation supports threads.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX_THREADS = libc::_SC_THREADS,
+     #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
+               target_os="linux", target_os = "macos", target_os="openbsd"))]
+     /// The implementation supports timeouts.
+     _POSIX_TIMEOUTS = libc::_SC_TIMEOUTS,
+     /// The implementation supports timers.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX_TIMERS = libc::_SC_TIMERS,
+     #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
+               target_os="linux", target_os = "macos", target_os="openbsd"))]
+@@ -2149,17 +2265,23 @@ pub enum SysconfVar {
+     /// using at least 64 bits.
+     _POSIX_V6_LPBIG_OFFBIG = libc::_SC_V6_LPBIG_OFFBIG,
+     /// The implementation supports the C-Language Binding option.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX2_C_BIND = libc::_SC_2_C_BIND,
+     /// The implementation supports the C-Language Development Utilities option.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX2_C_DEV = libc::_SC_2_C_DEV,
+     /// The implementation supports the Terminal Characteristics option.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX2_CHAR_TERM = libc::_SC_2_CHAR_TERM,
+     /// The implementation supports the FORTRAN Development Utilities option.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX2_FORT_DEV = libc::_SC_2_FORT_DEV,
+     /// The implementation supports the FORTRAN Runtime Utilities option.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX2_FORT_RUN = libc::_SC_2_FORT_RUN,
+     /// The implementation supports the creation of locales by the localedef
+     /// utility.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX2_LOCALEDEF = libc::_SC_2_LOCALEDEF,
+     #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
+               target_os="linux", target_os = "macos", target_os="netbsd",
+@@ -2193,26 +2315,34 @@ pub enum SysconfVar {
+     /// The implementation supports the Track Batch Job Request option.
+     _POSIX2_PBS_TRACK = libc::_SC_2_PBS_TRACK,
+     /// The implementation supports the Software Development Utilities option.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX2_SW_DEV = libc::_SC_2_SW_DEV,
+     /// The implementation supports the User Portability Utilities option.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX2_UPE = libc::_SC_2_UPE,
+     /// Integer value indicating version of the Shell and Utilities volume of
+     /// POSIX.1 to which the implementation conforms.
++    #[cfg(not(target_os = "redox"))]
+     _POSIX2_VERSION = libc::_SC_2_VERSION,
+     /// The size of a system page in bytes.
+     ///
+     /// POSIX also defines an alias named `PAGESIZE`, but Rust does not allow two
+     /// enum constants to have the same value, so nix omits `PAGESIZE`.
+     PAGE_SIZE = libc::_SC_PAGE_SIZE,
++    #[cfg(not(target_os = "redox"))]
+     PTHREAD_DESTRUCTOR_ITERATIONS = libc::_SC_THREAD_DESTRUCTOR_ITERATIONS,
++    #[cfg(not(target_os = "redox"))]
+     PTHREAD_KEYS_MAX = libc::_SC_THREAD_KEYS_MAX,
++    #[cfg(not(target_os = "redox"))]
+     PTHREAD_STACK_MIN = libc::_SC_THREAD_STACK_MIN,
++    #[cfg(not(target_os = "redox"))]
+     PTHREAD_THREADS_MAX = libc::_SC_THREAD_THREADS_MAX,
+     RE_DUP_MAX = libc::_SC_RE_DUP_MAX,
+     #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
+               target_os = "ios", target_os="linux", target_os = "macos",
+               target_os="openbsd"))]
+     RTSIG_MAX = libc::_SC_RTSIG_MAX,
++    #[cfg(not(target_os = "redox"))]
+     SEM_NSEMS_MAX = libc::_SC_SEM_NSEMS_MAX,
+     #[cfg(any(target_os="android", target_os="dragonfly", target_os="freebsd",
+               target_os = "ios", target_os="linux", target_os = "macos",
+@@ -2227,6 +2357,7 @@ pub enum SysconfVar {
+               target_os="linux", target_os = "macos", target_os="netbsd",
+               target_os="openbsd"))]
+     SYMLOOP_MAX = libc::_SC_SYMLOOP_MAX,
++    #[cfg(not(target_os = "redox"))]
+     TIMER_MAX = libc::_SC_TIMER_MAX,
+     TTY_NAME_MAX = libc::_SC_TTY_NAME_MAX,
+     TZNAME_MAX = libc::_SC_TZNAME_MAX,
+@@ -2257,6 +2388,7 @@ pub enum SysconfVar {
+     _XOPEN_REALTIME_THREADS = libc::_SC_XOPEN_REALTIME_THREADS,
+     /// The implementation supports the Issue 4, Version 2 Shared Memory Option
+     /// Group.
++    #[cfg(not(target_os = "redox"))]
+     _XOPEN_SHM = libc::_SC_XOPEN_SHM,
+     #[cfg(any(target_os="dragonfly", target_os="freebsd", target_os = "ios",
+               target_os="linux", target_os = "macos", target_os="openbsd"))]
+@@ -2309,9 +2441,8 @@ pub fn sysconf(var: SysconfVar) -> Result<Option<c_long>> {
+ 
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ mod pivot_root {
+-    use libc;
+-    use {Result, NixPath};
+-    use errno::Errno;
++    use crate::{Result, NixPath};
++    use crate::errno::Errno;
+ 
+     pub fn pivot_root<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
+             new_root: &P1, put_old: &P2) -> Result<()> {
+@@ -2330,9 +2461,8 @@ mod pivot_root {
+ #[cfg(any(target_os = "android", target_os = "freebsd",
+           target_os = "linux", target_os = "openbsd"))]
+ mod setres {
+-    use libc;
+-    use Result;
+-    use errno::Errno;
++    use crate::Result;
++    use crate::errno::Errno;
+     use super::{Uid, Gid};
+ 
+     /// Sets the real, effective, and saved uid.
+@@ -2392,3 +2522,308 @@ pub fn access<P: ?Sized + NixPath>(path: &P, amode: AccessFlags) -> Result<()> {
+     })?;
+     Errno::result(res).map(drop)
+ }
++
++/// Representation of a User, based on `libc::passwd`
++///
++/// The reason some fields in this struct are `String` and others are `CString` is because some
++/// fields are based on the user's locale, which could be non-UTF8, while other fields are
++/// guaranteed to conform to [`NAME_REGEX`](https://serverfault.com/a/73101/407341), which only
++/// contains ASCII.
++#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
++#[derive(Debug, Clone, PartialEq)]
++pub struct User {
++    /// Username
++    pub name: String,
++    /// User password (probably encrypted)
++    pub passwd: CString,
++    /// User ID
++    pub uid: Uid,
++    /// Group ID
++    pub gid: Gid,
++    /// User information
++    #[cfg(not(target_os = "android"))]
++    pub gecos: CString,
++    /// Home directory
++    pub dir: PathBuf,
++    /// Path to shell
++    pub shell: PathBuf,
++    /// Login class
++    #[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 = "fuchsia",
++                  target_os = "linux")))]
++    pub change: libc::time_t,
++    /// Expiration time of account
++    #[cfg(not(any(target_os = "android", target_os = "fuchsia",
++                  target_os = "linux")))]
++    pub expire: libc::time_t
++}
++
++#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
++impl From<&libc::passwd> for User {
++    fn from(pw: &libc::passwd) -> User {
++        unsafe {
++            User {
++                name: CStr::from_ptr((*pw).pw_name).to_string_lossy().into_owned(),
++                passwd: CString::new(CStr::from_ptr((*pw).pw_passwd).to_bytes()).unwrap(),
++                #[cfg(not(target_os = "android"))]
++                gecos: CString::new(CStr::from_ptr((*pw).pw_gecos).to_bytes()).unwrap(),
++                dir: PathBuf::from(OsStr::from_bytes(CStr::from_ptr((*pw).pw_dir).to_bytes())),
++                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 = "fuchsia",
++                              target_os = "linux")))]
++                class: CString::new(CStr::from_ptr((*pw).pw_class).to_bytes()).unwrap(),
++                #[cfg(not(any(target_os = "android", target_os = "fuchsia",
++                              target_os = "linux")))]
++                change: (*pw).pw_change,
++                #[cfg(not(any(target_os = "android", target_os = "fuchsia",
++                              target_os = "linux")))]
++                expire: (*pw).pw_expire
++            }
++        }
++    }
++}
++
++#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
++impl User {
++    fn from_anything<F>(f: F) -> Result<Option<Self>>
++    where
++        F: Fn(*mut libc::passwd,
++              *mut libc::c_char,
++              libc::size_t,
++              *mut *mut libc::passwd) -> libc::c_int
++    {
++        let buflimit = 16384;
++        let bufsize = match sysconf(SysconfVar::GETPW_R_SIZE_MAX) {
++            Ok(Some(n)) => n as usize,
++            Ok(None) | Err(_) => buflimit as usize,
++        };
++
++        let mut cbuf = Vec::with_capacity(bufsize);
++        let mut pwd = mem::MaybeUninit::<libc::passwd>::uninit();
++        let mut res = ptr::null_mut();
++
++        loop {
++            let error = f(pwd.as_mut_ptr(), cbuf.as_mut_ptr(), cbuf.capacity(), &mut res);
++            if error == 0 {
++                if res.is_null() {
++                    return Ok(None);
++                } else {
++                    let pwd = unsafe { pwd.assume_init() };
++                    return Ok(Some(User::from(&pwd)));
++                }
++            } else if Errno::last() == Errno::ERANGE {
++                // Trigger the internal buffer resizing logic.
++                reserve_double_buffer_size(&mut cbuf, buflimit)?;
++            } else {
++                return Err(Error::Sys(Errno::last()));
++            }
++        }
++    }
++
++    /// Get a user by UID.
++    ///
++    /// Internally, this function calls
++    /// [getpwuid_r(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html)
++    ///
++    /// # Examples
++    ///
++    /// ```
++    /// use nix::unistd::{Uid, User};
++    /// // Returns an Result<Option<User>>, thus the double unwrap.
++    /// let res = User::from_uid(Uid::from_raw(0)).unwrap().unwrap();
++    /// assert!(res.name == "root");
++    /// ```
++    pub fn from_uid(uid: Uid) -> Result<Option<Self>> {
++        User::from_anything(|pwd, cbuf, cap, res| {
++            unsafe { libc::getpwuid_r(uid.0, pwd, cbuf, cap, res) }
++        })
++    }
++
++    /// Get a user by name.
++    ///
++    /// Internally, this function calls
++    /// [getpwnam_r(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html)
++    ///
++    /// # Examples
++    ///
++    /// ```
++    /// use nix::unistd::User;
++    /// // Returns an Result<Option<User>>, thus the double unwrap.
++    /// let res = User::from_name("root").unwrap().unwrap();
++    /// assert!(res.name == "root");
++    /// ```
++    pub fn from_name(name: &str) -> Result<Option<Self>> {
++        let name = CString::new(name).unwrap();
++        User::from_anything(|pwd, cbuf, cap, res| {
++            unsafe { libc::getpwnam_r(name.as_ptr(), pwd, cbuf, cap, res) }
++        })
++    }
++}
++
++/// Representation of a Group, based on `libc::group`
++#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
++#[derive(Debug, Clone, PartialEq)]
++pub struct Group {
++    /// Group name
++    pub name: String,
++    /// Group password
++    pub passwd: CString,
++    /// Group ID
++    pub gid: Gid,
++    /// List of Group members
++    pub mem: Vec<String>
++}
++
++#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
++impl From<&libc::group> for Group {
++    fn from(gr: &libc::group) -> Group {
++        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)
++            }
++        }
++    }
++}
++
++#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
++impl Group {
++    unsafe fn members(mem: *mut *mut c_char) -> Vec<String> {
++        let mut ret = Vec::new();
++
++        for i in 0.. {
++            let u = mem.offset(i);
++            if (*u).is_null() {
++                break;
++            } else {
++                let s = CStr::from_ptr(*u).to_string_lossy().into_owned();
++                ret.push(s);
++            }
++        }
++
++        ret
++    }
++
++    fn from_anything<F>(f: F) -> Result<Option<Self>>
++    where
++        F: Fn(*mut libc::group,
++              *mut libc::c_char,
++              libc::size_t,
++              *mut *mut libc::group) -> libc::c_int
++    {
++        let buflimit = 16384;
++        let bufsize = match sysconf(SysconfVar::GETGR_R_SIZE_MAX) {
++            Ok(Some(n)) => n as usize,
++            Ok(None) | Err(_) => buflimit as usize,
++        };
++
++        let mut cbuf = Vec::with_capacity(bufsize);
++        let mut grp = mem::MaybeUninit::<libc::group>::uninit();
++        let mut res = ptr::null_mut();
++
++        loop {
++            let error = f(grp.as_mut_ptr(), cbuf.as_mut_ptr(), cbuf.capacity(), &mut res);
++            if error == 0 {
++                if res.is_null() {
++                    return Ok(None);
++                } else {
++                    let grp = unsafe { grp.assume_init() };
++                    return Ok(Some(Group::from(&grp)));
++                }
++            } else if Errno::last() == Errno::ERANGE {
++                // Trigger the internal buffer resizing logic.
++                reserve_double_buffer_size(&mut cbuf, buflimit)?;
++            } else {
++                return Err(Error::Sys(Errno::last()));
++            }
++        }
++    }
++
++    /// Get a group by GID.
++    ///
++    /// Internally, this function calls
++    /// [getgrgid_r(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html)
++    ///
++    /// # Examples
++    ///
++    // Disable this test on all OS except Linux as root group may not exist.
++    #[cfg_attr(not(target_os = "linux"), doc = " ```no_run")]
++    #[cfg_attr(target_os = "linux", doc = " ```")]
++    /// use nix::unistd::{Gid, Group};
++    /// // Returns an Result<Option<Group>>, thus the double unwrap.
++    /// let res = Group::from_gid(Gid::from_raw(0)).unwrap().unwrap();
++    /// assert!(res.name == "root");
++    /// ```
++    pub fn from_gid(gid: Gid) -> Result<Option<Self>> {
++        Group::from_anything(|grp, cbuf, cap, res| {
++            unsafe { libc::getgrgid_r(gid.0, grp, cbuf, cap, res) }
++        })
++    }
++
++    /// Get a group by name.
++    ///
++    /// Internally, this function calls
++    /// [getgrnam_r(3)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html)
++    ///
++    /// # Examples
++    ///
++    // Disable this test on all OS except Linux as root group may not exist.
++    #[cfg_attr(not(target_os = "linux"), doc = " ```no_run")]
++    #[cfg_attr(target_os = "linux", doc = " ```")]
++    /// use nix::unistd::Group;
++    /// // Returns an Result<Option<Group>>, thus the double unwrap.
++    /// let res = Group::from_name("root").unwrap().unwrap();
++    /// assert!(res.name == "root");
++    /// ```
++    pub fn from_name(name: &str) -> Result<Option<Self>> {
++        let name = CString::new(name).unwrap();
++        Group::from_anything(|grp, cbuf, cap, res| {
++            unsafe { libc::getgrnam_r(name.as_ptr(), grp, cbuf, cap, res) }
++        })
++    }
++}
++
++/// 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];
++    let c_buf = buf.as_mut_ptr() as *mut libc::c_char;
++
++    let ret = unsafe { libc::ttyname_r(fd, c_buf, buf.len()) };
++    if ret != 0 {
++        return Err(Error::Sys(Errno::from_i32(ret)));
++    }
++
++    let nul = buf.iter().position(|c| *c == b'\0').unwrap();
++    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/third_party/rust/nix/test/common/mod.rs b/third_party/rust/nix/test/common/mod.rs
+new file mode 100644
+index 0000000000000..a871b47041d3e
+--- /dev/null
++++ b/third_party/rust/nix/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/third_party/rust/nix/test/sys/mod.rs b/third_party/rust/nix/test/sys/mod.rs
+index 60a58dd106f19..14b03784a0a57 100644
+--- a/third_party/rust/nix/test/sys/mod.rs
++++ b/third_party/rust/nix/test/sys/mod.rs
+@@ -13,12 +13,17 @@ mod test_signal;
+ mod test_aio;
+ #[cfg(target_os = "linux")]
+ mod test_signalfd;
++#[cfg(not(target_os = "redox"))]
+ mod test_socket;
++#[cfg(not(target_os = "redox"))]
+ mod test_sockopt;
++#[cfg(not(target_os = "redox"))]
+ mod test_select;
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ mod test_sysinfo;
++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
+ mod test_termios;
++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
+ mod test_ioctl;
+ mod test_wait;
+ mod test_uio;
+@@ -36,3 +41,5 @@ mod test_pthread;
+           target_os = "netbsd",
+           target_os = "openbsd"))]
+ mod test_ptrace;
++#[cfg(any(target_os = "android", target_os = "linux"))]
++mod test_timerfd;
+diff --git a/third_party/rust/nix/test/sys/test_aio.rs b/third_party/rust/nix/test/sys/test_aio.rs
+index d4b09b0b81905..3878da94a6ef6 100644
+--- a/third_party/rust/nix/test/sys/test_aio.rs
++++ b/third_party/rust/nix/test/sys/test_aio.rs
+@@ -47,7 +47,7 @@ fn test_accessors() {
+ // our bindings.  So it's sufficient to check that AioCb.cancel returned any
+ // AioCancelStat value.
+ #[test]
+-#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++#[cfg_attr(target_env = "musl", ignore)]
+ fn test_cancel() {
+     let wbuf: &[u8] = b"CDEF";
+ 
+@@ -72,7 +72,7 @@ fn test_cancel() {
+ 
+ // Tests using aio_cancel_all for all outstanding IOs.
+ #[test]
+-#[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++#[cfg_attr(target_env = "musl", ignore)]
+ fn test_aio_cancel_all() {
+     let wbuf: &[u8] = b"CDEF";
+ 
+@@ -133,6 +133,13 @@ fn test_fsync_error() {
+ 
+ #[test]
+ #[cfg_attr(all(target_env = "musl", target_arch = "x86_64"), ignore)]
++// On Travis, aio_suspend hits an assertion within glibc.  This is either a bug
++// in Travis's version of glibc or Linux.  Either way, we must skip the test.
++// 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";
+@@ -160,7 +167,12 @@ fn test_aio_suspend() {
+     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)) {
+@@ -168,8 +180,8 @@ fn test_aio_suspend() {
+         }
+     }
+ 
+-    assert!(wcb.aio_return().unwrap() as usize == WBUF.len());
+-    assert!(rcb.aio_return().unwrap() as usize == rlen);
++    assert_eq!(wcb.aio_return().unwrap() as usize, WBUF.len());
++    assert_eq!(rcb.aio_return().unwrap() as usize, rlen);
+ }
+ 
+ // Test a simple aio operation with no completion notification.  We must poll
+@@ -192,11 +204,11 @@ fn test_read() {
+         aiocb.read().unwrap();
+ 
+         let err = poll_aio(&mut aiocb);
+-        assert!(err == Ok(()));
+-        assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len());
++        assert_eq!(err, Ok(()));
++        assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len());
+     }
+ 
+-    assert!(EXPECT == rbuf.deref().deref());
++    assert_eq!(EXPECT, rbuf.deref().deref());
+ }
+ 
+ /// `AioCb::read` should not modify the `AioCb` object if `libc::aio_read`
+@@ -238,11 +250,11 @@ fn test_read_into_mut_slice() {
+         aiocb.read().unwrap();
+ 
+         let err = poll_aio(&mut aiocb);
+-        assert!(err == Ok(()));
+-        assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len());
++        assert_eq!(err, Ok(()));
++        assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len());
+     }
+ 
+-    assert!(rbuf == EXPECT);
++    assert_eq!(rbuf, EXPECT);
+ }
+ 
+ // Tests from_ptr
+@@ -268,11 +280,11 @@ fn test_read_into_pointer() {
+         aiocb.read().unwrap();
+ 
+         let err = poll_aio(&mut aiocb);
+-        assert!(err == Ok(()));
+-        assert!(aiocb.aio_return().unwrap() as usize == EXPECT.len());
++        assert_eq!(err, Ok(()));
++        assert_eq!(aiocb.aio_return().unwrap() as usize, EXPECT.len());
+     }
+ 
+-    assert!(rbuf == EXPECT);
++    assert_eq!(rbuf, EXPECT);
+ }
+ 
+ // Test reading into an immutable buffer.  It should fail
+@@ -314,13 +326,13 @@ fn test_write() {
+     aiocb.write().unwrap();
+ 
+     let err = poll_aio(&mut aiocb);
+-    assert!(err == Ok(()));
+-    assert!(aiocb.aio_return().unwrap() as usize == wbuf.len());
++    assert_eq!(err, Ok(()));
++    assert_eq!(aiocb.aio_return().unwrap() as usize, wbuf.len());
+ 
+     f.seek(SeekFrom::Start(0)).unwrap();
+     let len = f.read_to_end(&mut rbuf).unwrap();
+-    assert!(len == EXPECT.len());
+-    assert!(rbuf == EXPECT);
++    assert_eq!(len, EXPECT.len());
++    assert_eq!(rbuf, EXPECT);
+ }
+ 
+ // Tests `AioCb::from_boxed_slice` with `Bytes`
+@@ -344,13 +356,13 @@ fn test_write_bytes() {
+     aiocb.write().unwrap();
+ 
+     let err = poll_aio(&mut aiocb);
+-    assert!(err == Ok(()));
+-    assert!(aiocb.aio_return().unwrap() as usize == expected_len);
++    assert_eq!(err, Ok(()));
++    assert_eq!(aiocb.aio_return().unwrap() as usize, expected_len);
+ 
+     f.seek(SeekFrom::Start(0)).unwrap();
+     let len = f.read_to_end(&mut rbuf).unwrap();
+-    assert!(len == EXPECT.len());
+-    assert!(rbuf == EXPECT);
++    assert_eq!(len, EXPECT.len());
++    assert_eq!(rbuf, EXPECT);
+ }
+ 
+ // Tests `AioCb::from_boxed_mut_slice` with `BytesMut`
+@@ -402,13 +414,13 @@ fn test_write_from_pointer() {
+     aiocb.write().unwrap();
+ 
+     let err = poll_aio(&mut aiocb);
+-    assert!(err == Ok(()));
+-    assert!(aiocb.aio_return().unwrap() as usize == wbuf.len());
++    assert_eq!(err, Ok(()));
++    assert_eq!(aiocb.aio_return().unwrap() as usize, wbuf.len());
+ 
+     f.seek(SeekFrom::Start(0)).unwrap();
+     let len = f.read_to_end(&mut rbuf).unwrap();
+-    assert!(len == EXPECT.len());
+-    assert!(rbuf == EXPECT);
++    assert_eq!(len, EXPECT.len());
++    assert_eq!(rbuf, EXPECT);
+ }
+ 
+ /// `AioCb::write` should not modify the `AioCb` object if `libc::aio_write`
+@@ -441,7 +453,7 @@ extern fn sigfunc(_: c_int) {
+ #[test]
+ #[cfg_attr(any(all(target_env = "musl", target_arch = "x86_64"), target_arch = "mips", target_arch = "mips64"), ignore)]
+ fn test_write_sigev_signal() {
+-    let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
+     let sa = SigAction::new(SigHandler::Handler(sigfunc),
+                             SaFlags::SA_RESETHAND,
+                             SigSet::empty());
+@@ -469,11 +481,11 @@ fn test_write_sigev_signal() {
+         thread::sleep(time::Duration::from_millis(10));
+     }
+ 
+-    assert!(aiocb.aio_return().unwrap() as usize == WBUF.len());
++    assert_eq!(aiocb.aio_return().unwrap() as usize, WBUF.len());
+     f.seek(SeekFrom::Start(0)).unwrap();
+     let len = f.read_to_end(&mut rbuf).unwrap();
+-    assert!(len == EXPECT.len());
+-    assert!(rbuf == EXPECT);
++    assert_eq!(len, EXPECT.len());
++    assert_eq!(rbuf, EXPECT);
+ }
+ 
+ // Test LioCb::listio with LIO_WAIT, so all AIO ops should be complete by the
+@@ -512,15 +524,15 @@ fn test_liocb_listio_wait() {
+         let err = liocb.listio(LioMode::LIO_WAIT, SigevNotify::SigevNone);
+         err.expect("lio_listio");
+ 
+-        assert!(liocb.aio_return(0).unwrap() as usize == WBUF.len());
+-        assert!(liocb.aio_return(1).unwrap() as usize == rlen);
++        assert_eq!(liocb.aio_return(0).unwrap() as usize, WBUF.len());
++        assert_eq!(liocb.aio_return(1).unwrap() as usize, rlen);
+     }
+-    assert!(rbuf.deref().deref() == b"3456");
++    assert_eq!(rbuf.deref().deref(), b"3456");
+ 
+     f.seek(SeekFrom::Start(0)).unwrap();
+     let len = f.read_to_end(&mut rbuf2).unwrap();
+-    assert!(len == EXPECT.len());
+-    assert!(rbuf2 == EXPECT);
++    assert_eq!(len, EXPECT.len());
++    assert_eq!(rbuf2, EXPECT);
+ }
+ 
+ // Test LioCb::listio with LIO_NOWAIT and no SigEvent, so we must use some other
+@@ -561,15 +573,15 @@ fn test_liocb_listio_nowait() {
+ 
+         poll_aio(&mut liocb.aiocbs[0]).unwrap();
+         poll_aio(&mut liocb.aiocbs[1]).unwrap();
+-        assert!(liocb.aiocbs[0].aio_return().unwrap() as usize == WBUF.len());
+-        assert!(liocb.aiocbs[1].aio_return().unwrap() as usize == rlen);
++        assert_eq!(liocb.aiocbs[0].aio_return().unwrap() as usize, WBUF.len());
++        assert_eq!(liocb.aiocbs[1].aio_return().unwrap() as usize, rlen);
+     }
+-    assert!(rbuf.deref().deref() == b"3456");
++    assert_eq!(rbuf.deref().deref(), b"3456");
+ 
+     f.seek(SeekFrom::Start(0)).unwrap();
+     let len = f.read_to_end(&mut rbuf2).unwrap();
+-    assert!(len == EXPECT.len());
+-    assert!(rbuf2 == EXPECT);
++    assert_eq!(len, EXPECT.len());
++    assert_eq!(rbuf2, EXPECT);
+ }
+ 
+ // Test LioCb::listio with LIO_NOWAIT and a SigEvent to indicate when all
+@@ -579,7 +591,7 @@ fn test_liocb_listio_nowait() {
+ #[cfg(not(any(target_os = "ios", target_os = "macos")))]
+ #[cfg_attr(any(target_arch = "mips", target_arch = "mips64", target_env = "musl"), ignore)]
+ fn test_liocb_listio_signal() {
+-    let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
+     const INITIAL: &[u8] = b"abcdef123456";
+     const WBUF: &[u8] = b"CDEF";
+     let mut rbuf = vec![0; 4];
+@@ -620,15 +632,15 @@ fn test_liocb_listio_signal() {
+             thread::sleep(time::Duration::from_millis(10));
+         }
+ 
+-        assert!(liocb.aiocbs[0].aio_return().unwrap() as usize == WBUF.len());
+-        assert!(liocb.aiocbs[1].aio_return().unwrap() as usize == rlen);
++        assert_eq!(liocb.aiocbs[0].aio_return().unwrap() as usize, WBUF.len());
++        assert_eq!(liocb.aiocbs[1].aio_return().unwrap() as usize, rlen);
+     }
+-    assert!(rbuf.deref().deref() == b"3456");
++    assert_eq!(rbuf.deref().deref(), b"3456");
+ 
+     f.seek(SeekFrom::Start(0)).unwrap();
+     let len = f.read_to_end(&mut rbuf2).unwrap();
+-    assert!(len == EXPECT.len());
+-    assert!(rbuf2 == EXPECT);
++    assert_eq!(len, EXPECT.len());
++    assert_eq!(rbuf2, EXPECT);
+ }
+ 
+ // Try to use LioCb::listio to read into an immutable buffer.  It should fail
+diff --git a/third_party/rust/nix/test/sys/test_aio_drop.rs b/third_party/rust/nix/test/sys/test_aio_drop.rs
+index 492da401ef726..784ee3ef6c75e 100644
+--- a/third_party/rust/nix/test/sys/test_aio_drop.rs
++++ b/third_party/rust/nix/test/sys/test_aio_drop.rs
+@@ -1,6 +1,3 @@
+-extern crate nix;
+-extern crate tempfile;
+-
+ // Test dropping an AioCb that hasn't yet finished.
+ // This must happen in its own process, because on OSX this test seems to hose
+ // the AIO subsystem and causes subsequent tests to fail
+@@ -12,6 +9,7 @@ extern crate tempfile;
+               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/third_party/rust/nix/test/sys/test_ioctl.rs b/third_party/rust/nix/test/sys/test_ioctl.rs
+index 0a439b3346f53..fa4510a69c089 100644
+--- a/third_party/rust/nix/test/sys/test_ioctl.rs
++++ b/third_party/rust/nix/test/sys/test_ioctl.rs
+@@ -33,22 +33,22 @@ mod linux {
+     #[test]
+     fn test_op_none() {
+         if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){
+-            assert_eq!(request_code_none!(b'q', 10), 0x2000_710A);
+-            assert_eq!(request_code_none!(b'a', 255), 0x2000_61FF);
++            assert_eq!(request_code_none!(b'q', 10) as u32, 0x2000_710A);
++            assert_eq!(request_code_none!(b'a', 255) as u32, 0x2000_61FF);
+         } else {
+-            assert_eq!(request_code_none!(b'q', 10), 0x0000_710A);
+-            assert_eq!(request_code_none!(b'a', 255), 0x0000_61FF);
++            assert_eq!(request_code_none!(b'q', 10) as u32, 0x0000_710A);
++            assert_eq!(request_code_none!(b'a', 255) as u32, 0x0000_61FF);
+         }
+     }
+ 
+     #[test]
+     fn test_op_write() {
+         if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){
+-            assert_eq!(request_code_write!(b'z', 10, 1), 0x8001_7A0A);
+-            assert_eq!(request_code_write!(b'z', 10, 512), 0x8200_7A0A);
++            assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x8001_7A0A);
++            assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x8200_7A0A);
+         } else {
+-            assert_eq!(request_code_write!(b'z', 10, 1), 0x4001_7A0A);
+-            assert_eq!(request_code_write!(b'z', 10, 512), 0x4200_7A0A);
++            assert_eq!(request_code_write!(b'z', 10, 1) as u32, 0x4001_7A0A);
++            assert_eq!(request_code_write!(b'z', 10, 512) as u32, 0x4200_7A0A);
+         }
+     }
+ 
+@@ -56,9 +56,11 @@ mod linux {
+     #[test]
+     fn test_op_write_64() {
+         if cfg!(any(target_arch = "mips64", target_arch="powerpc64")){
+-            assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A);
++            assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32) as u32,
++                       0x8000_7A0A);
+         } else {
+-            assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A);
++            assert_eq!(request_code_write!(b'z', 10, (1 as u64) << 32) as u32,
++                       0x4000_7A0A);
+         }
+ 
+     }
+@@ -66,11 +68,11 @@ mod linux {
+     #[test]
+     fn test_op_read() {
+         if cfg!(any(target_arch = "mips", target_arch = "mips64", target_arch="powerpc", target_arch="powerpc64")){
+-            assert_eq!(request_code_read!(b'z', 10, 1), 0x4001_7A0A);
+-            assert_eq!(request_code_read!(b'z', 10, 512), 0x4200_7A0A);
++            assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x4001_7A0A);
++            assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x4200_7A0A);
+         } else {
+-            assert_eq!(request_code_read!(b'z', 10, 1), 0x8001_7A0A);
+-            assert_eq!(request_code_read!(b'z', 10, 512), 0x8200_7A0A);
++            assert_eq!(request_code_read!(b'z', 10, 1) as u32, 0x8001_7A0A);
++            assert_eq!(request_code_read!(b'z', 10, 512) as u32, 0x8200_7A0A);
+         }
+     }
+ 
+@@ -78,22 +80,25 @@ mod linux {
+     #[test]
+     fn test_op_read_64() {
+         if cfg!(any(target_arch = "mips64", target_arch="powerpc64")){
+-            assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32), 0x4000_7A0A);
++            assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32) as u32,
++                       0x4000_7A0A);
+         } else {
+-            assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32), 0x8000_7A0A);
++            assert_eq!(request_code_read!(b'z', 10, (1 as u64) << 32) as u32,
++                       0x8000_7A0A);
+         }
+     }
+ 
+     #[test]
+     fn test_op_read_write() {
+-        assert_eq!(request_code_readwrite!(b'z', 10, 1), 0xC001_7A0A);
+-        assert_eq!(request_code_readwrite!(b'z', 10, 512), 0xC200_7A0A);
++        assert_eq!(request_code_readwrite!(b'z', 10, 1) as u32, 0xC001_7A0A);
++        assert_eq!(request_code_readwrite!(b'z', 10, 512) as u32, 0xC200_7A0A);
+     }
+ 
+     #[cfg(target_pointer_width = "64")]
+     #[test]
+     fn test_op_read_write_64() {
+-        assert_eq!(request_code_readwrite!(b'z', 10, (1 as u64) << 32), 0xC000_7A0A);
++        assert_eq!(request_code_readwrite!(b'z', 10, (1 as u64) << 32) as u32,
++                   0xC000_7A0A);
+     }
+ }
+ 
+@@ -177,7 +182,7 @@ mod linux_ioctls {
+     #[test]
+     fn test_ioctl_read_bad() {
+         let file = tempfile().unwrap();
+-        let mut termios = unsafe { mem::uninitialized() };
++        let mut termios = unsafe { mem::zeroed() };
+         let res = unsafe { tcgets(file.as_raw_fd(), &mut termios) };
+         assert_eq!(res, Err(Sys(ENOTTY)));
+     }
+@@ -194,7 +199,7 @@ mod linux_ioctls {
+     #[test]
+     fn test_ioctl_write_ptr_bad() {
+         let file = tempfile().unwrap();
+-        let termios: termios = unsafe { mem::uninitialized() };
++        let termios: termios = unsafe { mem::zeroed() };
+         let res = unsafe { tcsets(file.as_raw_fd(), &termios) };
+         assert_eq!(res, Err(Sys(ENOTTY)));
+     }
+@@ -245,7 +250,7 @@ mod linux_ioctls {
+     #[test]
+     fn test_ioctl_read() {
+         let file = tempfile().unwrap();
+-        let mut data: v4l2_audio = unsafe { mem::uninitialized() };
++        let mut data: v4l2_audio = unsafe { mem::zeroed() };
+         let res = unsafe { g_audio(file.as_raw_fd(), &mut data) };
+         assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
+     }
+@@ -255,7 +260,7 @@ mod linux_ioctls {
+     #[test]
+     fn test_ioctl_readwrite() {
+         let file = tempfile().unwrap();
+-        let mut data: v4l2_audio = unsafe { mem::uninitialized() };
++        let mut data: v4l2_audio = unsafe { mem::zeroed() };
+         let res = unsafe { enum_audio(file.as_raw_fd(), &mut data) };
+         assert!(res == Err(Sys(ENOTTY)) || res == Err(Sys(ENOSYS)));
+     }
+@@ -318,7 +323,7 @@ mod freebsd_ioctls {
+     #[test]
+     fn test_ioctl_read() {
+         let file = tempfile().unwrap();
+-        let mut termios = unsafe { mem::uninitialized() };
++        let mut termios = unsafe { mem::zeroed() };
+         let res = unsafe { tiocgeta(file.as_raw_fd(), &mut termios) };
+         assert_eq!(res, Err(Sys(ENOTTY)));
+     }
+@@ -327,7 +332,7 @@ mod freebsd_ioctls {
+     #[test]
+     fn test_ioctl_write_ptr() {
+         let file = tempfile().unwrap();
+-        let termios: termios = unsafe { mem::uninitialized() };
++        let termios: termios = unsafe { mem::zeroed() };
+         let res = unsafe { tiocseta(file.as_raw_fd(), &termios) };
+         assert_eq!(res, Err(Sys(ENOTTY)));
+     }
+diff --git a/third_party/rust/nix/test/sys/test_lio_listio_resubmit.rs b/third_party/rust/nix/test/sys/test_lio_listio_resubmit.rs
+index 19ee3facf87d7..0795370b8c448 100644
+--- a/third_party/rust/nix/test/sys/test_lio_listio_resubmit.rs
++++ b/third_party/rust/nix/test/sys/test_lio_listio_resubmit.rs
+@@ -4,10 +4,6 @@
+ // we must disable the test here rather than in Cargo.toml
+ #![cfg(target_os = "freebsd")]
+ 
+-extern crate nix;
+-extern crate sysctl;
+-extern crate tempfile;
+-
+ use nix::Error;
+ use nix::errno::*;
+ use nix::libc::off_t;
+diff --git a/third_party/rust/nix/test/sys/test_mman.rs b/third_party/rust/nix/test/sys/test_mman.rs
+new file mode 100644
+index 0000000000000..152fff69c24de
+--- /dev/null
++++ b/third_party/rust/nix/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/third_party/rust/nix/test/sys/test_pthread.rs b/third_party/rust/nix/test/sys/test_pthread.rs
+index 8928010087a13..1fc3dd900f382 100644
+--- a/third_party/rust/nix/test/sys/test_pthread.rs
++++ b/third_party/rust/nix/test/sys/test_pthread.rs
+@@ -1,13 +1,13 @@
+ use nix::sys::pthread::*;
+ 
+-#[cfg(target_env = "musl")]
++#[cfg(any(target_env = "musl", target_os = "redox"))]
+ #[test]
+ fn test_pthread_self() {
+     let tid = pthread_self();
+     assert!(tid != ::std::ptr::null_mut());
+ }
+ 
+-#[cfg(not(target_env = "musl"))]
++#[cfg(not(any(target_env = "musl", target_os = "redox")))]
+ #[test]
+ fn test_pthread_self() {
+     let tid = pthread_self();
+diff --git a/third_party/rust/nix/test/sys/test_ptrace.rs b/third_party/rust/nix/test/sys/test_ptrace.rs
+index 24d9b522ee4e5..b9793b39c54ae 100644
+--- a/third_party/rust/nix/test/sys/test_ptrace.rs
++++ b/third_party/rust/nix/test/sys/test_ptrace.rs
+@@ -8,10 +8,13 @@ use nix::sys::ptrace::Options;
+ #[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.
+     // FIXME: qemu-user doesn't implement ptrace on all arches, so permit ENOSYS
++    require_capability!(CAP_SYS_PTRACE);
+     let err = ptrace::attach(getpid()).unwrap_err();
+     assert!(err == Error::Sys(Errno::EPERM) || err == Error::Sys(Errno::EINVAL) ||
+             err == Error::Sys(Errno::ENOSYS));
+@@ -21,6 +24,7 @@ fn test_ptrace() {
+ #[test]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ fn test_ptrace_setoptions() {
++    require_capability!(CAP_SYS_PTRACE);
+     let err = ptrace::setoptions(getpid(), Options::PTRACE_O_TRACESYSGOOD).unwrap_err();
+     assert!(err != Error::UnsupportedOperation);
+ }
+@@ -29,6 +33,7 @@ fn test_ptrace_setoptions() {
+ #[test]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ fn test_ptrace_getevent() {
++    require_capability!(CAP_SYS_PTRACE);
+     let err = ptrace::getevent(getpid()).unwrap_err();
+     assert!(err != Error::UnsupportedOperation);
+ }
+@@ -37,6 +42,7 @@ fn test_ptrace_getevent() {
+ #[test]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ fn test_ptrace_getsiginfo() {
++    require_capability!(CAP_SYS_PTRACE);
+     if let Err(Error::UnsupportedOperation) = ptrace::getsiginfo(getpid()) {
+         panic!("ptrace_getsiginfo returns Error::UnsupportedOperation!");
+     }
+@@ -46,7 +52,8 @@ fn test_ptrace_getsiginfo() {
+ #[test]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ fn test_ptrace_setsiginfo() {
+-    let siginfo = unsafe { mem::uninitialized() };
++    require_capability!(CAP_SYS_PTRACE);
++    let siginfo = unsafe { mem::zeroed() };
+     if let Err(Error::UnsupportedOperation) = ptrace::setsiginfo(getpid(), &siginfo) {
+         panic!("ptrace_setsiginfo returns Error::UnsupportedOperation!");
+     }
+@@ -61,7 +68,9 @@ fn test_ptrace_cont() {
+     use nix::unistd::fork;
+     use nix::unistd::ForkResult::*;
+ 
+-    let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++    require_capability!(CAP_SYS_PTRACE);
++
++    let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+     // FIXME: qemu-user doesn't implement ptrace on all architectures
+     // and retunrs ENOSYS in this case.
+@@ -74,7 +83,7 @@ fn test_ptrace_cont() {
+         return;
+     }
+ 
+-    match fork().expect("Error: Fork Failed") {
++    match unsafe{fork()}.expect("Error: Fork Failed") {
+         Child => {
+             ptrace::traceme().unwrap();
+             // As recommended by ptrace(2), raise SIGTRAP to pause the child
+@@ -91,7 +100,7 @@ fn test_ptrace_cont() {
+             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.
+@@ -105,3 +114,65 @@ fn test_ptrace_cont() {
+         },
+     }
+ }
++
++// ptrace::{setoptions, getregs} are only available in these platforms
++#[cfg(all(target_os = "linux",
++          any(target_arch = "x86_64",
++              target_arch = "x86"),
++          target_env = "gnu"))]
++#[test]
++fn test_ptrace_syscall() {
++    use nix::sys::signal::kill;
++    use nix::sys::ptrace;
++    use nix::sys::signal::Signal;
++    use nix::sys::wait::{waitpid, WaitStatus};
++    use nix::unistd::fork;
++    use nix::unistd::getpid;
++    use nix::unistd::ForkResult::*;
++
++    require_capability!(CAP_SYS_PTRACE);
++
++    let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++
++    match unsafe{fork()}.expect("Error: Fork Failed") {
++        Child => {
++            ptrace::traceme().unwrap();
++            // first sigstop until parent is ready to continue
++            let pid = getpid();
++            kill(pid, Signal::SIGSTOP).unwrap();
++            kill(pid, Signal::SIGTERM).unwrap();
++            unsafe { ::libc::_exit(0); }
++        },
++
++        Parent { child } => {
++            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGSTOP)));
++
++            // set this option to recognize syscall-stops
++            ptrace::setoptions(child, ptrace::Options::PTRACE_O_TRACESYSGOOD).unwrap();
++
++            #[cfg(target_arch = "x86_64")]
++            let get_syscall_id = || ptrace::getregs(child).unwrap().orig_rax as libc::c_long;
++
++            #[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();
++            assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
++            assert_eq!(get_syscall_id(), ::libc::SYS_kill);
++
++            // kill exit
++            ptrace::syscall(child, None).unwrap();
++            assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
++            assert_eq!(get_syscall_id(), ::libc::SYS_kill);
++
++            // receive signal
++            ptrace::syscall(child, None).unwrap();
++            assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, Signal::SIGTERM)));
++
++            // inject signal
++            ptrace::syscall(child, Signal::SIGTERM).unwrap();
++            assert_eq!(waitpid(child, None), Ok(WaitStatus::Signaled(child, Signal::SIGTERM, false)));
++        },
++    }
++}
+diff --git a/third_party/rust/nix/test/sys/test_select.rs b/third_party/rust/nix/test/sys/test_select.rs
+index cf68700c5e16f..37951086c2d8d 100644
+--- a/third_party/rust/nix/test/sys/test_select.rs
++++ b/third_party/rust/nix/test/sys/test_select.rs
+@@ -5,7 +5,7 @@ use nix::sys::time::{TimeSpec, TimeValLike};
+ 
+ #[test]
+ pub fn test_pselect() {
+-    let _mtx = ::SIGNAL_MTX
++    let _mtx = crate::SIGNAL_MTX
+         .lock()
+         .expect("Mutex got poisoned by another test");
+ 
+diff --git a/third_party/rust/nix/test/sys/test_signal.rs b/third_party/rust/nix/test/sys/test_signal.rs
+index 8780763f773ef..ae22527fde278 100644
+--- a/third_party/rust/nix/test/sys/test_signal.rs
++++ b/third_party/rust/nix/test/sys/test_signal.rs
+@@ -1,7 +1,9 @@
+ use libc;
++#[cfg(not(target_os = "redox"))]
+ use nix::Error;
+ use nix::sys::signal::*;
+ use nix::unistd::*;
++use std::convert::TryFrom;
+ use std::sync::atomic::{AtomicBool, Ordering};
+ 
+ #[test]
+@@ -10,6 +12,7 @@ fn test_kill_none() {
+ }
+ 
+ #[test]
++#[cfg(not(target_os = "fuchsia"))]
+ fn test_killpg_none() {
+     killpg(getpgrp(), None)
+         .expect("Should be able to send signal to my process group.");
+@@ -17,6 +20,8 @@ fn test_killpg_none() {
+ 
+ #[test]
+ fn test_old_sigaction_flags() {
++    let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++
+     extern "C" fn handler(_: ::libc::c_int) {}
+     let act = SigAction::new(
+         SigHandler::Handler(handler),
+@@ -37,7 +42,7 @@ fn test_sigprocmask_noop() {
+ 
+ #[test]
+ fn test_sigprocmask() {
+-    let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+     // This needs to be a signal that rust doesn't use in the test harness.
+     const SIGNAL: Signal = Signal::SIGCHLD;
+@@ -75,16 +80,25 @@ lazy_static! {
+ }
+ 
+ extern fn test_sigaction_handler(signal: libc::c_int) {
+-    let signal = Signal::from_c_int(signal).unwrap();
++    let signal = Signal::try_from(signal).unwrap();
+     SIGNALED.store(signal == Signal::SIGINT, Ordering::Relaxed);
+ }
+ 
+-extern fn test_sigaction_action(_: libc::c_int, _: *mut libc::siginfo_t, _: *mut libc::c_void) {
++#[cfg(not(target_os = "redox"))]
++extern fn test_sigaction_action(_: libc::c_int, _: *mut libc::siginfo_t, _: *mut libc::c_void) {}
++
++#[test]
++#[cfg(not(target_os = "redox"))]
++fn test_signal_sigaction() {
++    let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++
++    let action_handler = SigHandler::SigAction(test_sigaction_action);
++    assert_eq!(unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(), Error::UnsupportedOperation);
+ }
+ 
+ #[test]
+ fn test_signal() {
+-    let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+     unsafe { signal(Signal::SIGINT, SigHandler::SigIgn) }.unwrap();
+     raise(Signal::SIGINT).unwrap();
+@@ -96,9 +110,6 @@ fn test_signal() {
+     assert!(SIGNALED.load(Ordering::Relaxed));
+     assert_eq!(unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap(), handler);
+ 
+-    let action_handler = SigHandler::SigAction(test_sigaction_action);
+-    assert_eq!(unsafe { signal(Signal::SIGINT, action_handler) }.unwrap_err(), Error::UnsupportedOperation);
+-
+     // Restore default signal handler
+     unsafe { signal(Signal::SIGINT, SigHandler::SigDfl) }.unwrap();
+ }
+diff --git a/third_party/rust/nix/test/sys/test_signalfd.rs b/third_party/rust/nix/test/sys/test_signalfd.rs
+index a3b6098841f1c..af04c222852d8 100644
+--- a/third_party/rust/nix/test/sys/test_signalfd.rs
++++ b/third_party/rust/nix/test/sys/test_signalfd.rs
+@@ -1,10 +1,12 @@
++use std::convert::TryFrom;
++
+ #[test]
+ fn test_signalfd() {
+     use nix::sys::signalfd::SignalFd;
+     use nix::sys::signal::{self, raise, Signal, SigSet};
+ 
+     // Grab the mutex for altering signals so we don't interfere with other tests.
+-    let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+     // Block the SIGUSR1 signal from automatic processing for this thread
+     let mut mask = SigSet::empty();
+@@ -20,6 +22,6 @@ fn test_signalfd() {
+ 
+     // And now catch that same signal.
+     let res = fd.read_signal().unwrap().unwrap();
+-    let signo = Signal::from_c_int(res.ssi_signo as i32).unwrap();
++    let signo = Signal::try_from(res.ssi_signo as i32).unwrap();
+     assert_eq!(signo, signal::SIGUSR1);
+ }
+diff --git a/third_party/rust/nix/test/sys/test_socket.rs b/third_party/rust/nix/test/sys/test_socket.rs
+index 7e64d2b77f071..2b89a45336f3e 100644
+--- a/third_party/rust/nix/test/sys/test_socket.rs
++++ b/third_party/rust/nix/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::slice;
+ 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() {
+@@ -106,7 +107,7 @@ pub fn test_addr_equality_abstract() {
+     assert_eq!(addr1, addr2);
+     assert_eq!(calculate_hash(&addr1), calculate_hash(&addr2));
+ 
+-    addr2.0.sun_path[18] = 127;
++    addr2.0.sun_path[17] = 127;
+     assert_ne!(addr1, addr2);
+     assert_ne!(calculate_hash(&addr1), calculate_hash(&addr2));
+ }
+@@ -117,16 +118,13 @@ pub fn test_addr_equality_abstract() {
+ pub fn test_abstract_uds_addr() {
+     let empty = String::new();
+     let addr = UnixAddr::new_abstract(empty.as_bytes()).unwrap();
+-    let sun_path = [0u8; 107];
++    let sun_path: [u8; 0] = [];
+     assert_eq!(addr.as_abstract(), Some(&sun_path[..]));
+ 
+     let name = String::from("nix\0abstract\0test");
+     let addr = UnixAddr::new_abstract(name.as_bytes()).unwrap();
+     let sun_path = [
+-        110u8, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116, 0, 0, 0, 0,
+-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
++        110u8, 105, 120, 0, 97, 98, 115, 116, 114, 97, 99, 116, 0, 116, 101, 115, 116
+     ];
+     assert_eq!(addr.as_abstract(), Some(&sun_path[..]));
+     assert_eq!(addr.path(), None);
+@@ -164,6 +162,360 @@ pub fn test_socketpair() {
+     assert_eq!(&buf[..], b"hello");
+ }
+ 
++mod recvfrom {
++    use nix::Result;
++    use nix::sys::socket::*;
++    use std::thread;
++    use super::*;
++
++    const MSG: &'static [u8] = b"Hello, World!";
++
++    fn sendrecv<Fs, Fr>(rsock: RawFd, ssock: RawFd, f_send: Fs, mut f_recv: Fr) -> Option<SockAddr>
++        where
++            Fs: Fn(RawFd, &[u8], MsgFlags) -> Result<usize> + Send + 'static,
++            Fr: FnMut(usize, Option<SockAddr>),
++    {
++        let mut buf: [u8; 13] = [0u8; 13];
++        let mut l = 0;
++        let mut from = None;
++
++        let send_thread = thread::spawn(move || {
++            let mut l = 0;
++            while l < std::mem::size_of_val(MSG) {
++                l += f_send(ssock, &MSG[l..], MsgFlags::empty()).unwrap();
++            }
++        });
++
++        while l < std::mem::size_of_val(MSG) {
++            let (len, from_) = recvfrom(rsock, &mut buf[l..]).unwrap();
++            f_recv(len, from_);
++            from = from_;
++            l += len;
++        }
++        assert_eq!(&buf, MSG);
++        send_thread.join().unwrap();
++        from
++    }
++
++    #[test]
++    pub fn stream() {
++        let (fd2, fd1) = socketpair(AddressFamily::Unix, SockType::Stream,
++                                    None, SockFlag::empty()).unwrap();
++        // Ignore from for stream sockets
++        let _ = sendrecv(fd1, fd2, |s, m, flags| {
++            send(s, m, flags)
++        }, |_, _| {});
++    }
++
++    #[test]
++    pub fn udp() {
++        let std_sa = SocketAddr::from_str("127.0.0.1:6789").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 from = sendrecv(rsock, ssock, move |s, m, flags| {
++            sendto(s, m, &sock_addr, flags)
++        },|_, _| {});
++        // UDP sockets should set the from address
++        assert_eq!(AddressFamily::Inet, from.unwrap().family());
++    }
++
++    #[cfg(target_os = "linux")]
++    mod udp_offload {
++        use super::*;
++        use nix::sys::uio::IoVec;
++        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");
++
++            // In this test, we send the data and provide a GSO segment size.
++            // Since we are sending the buffer of size 13, six UDP packets
++            // with size 2 and two UDP packet with size 1 will be sent.
++            let segment_size: u16 = 2;
++
++            let std_sa = SocketAddr::from_str("127.0.0.1:6791").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();
++
++            setsockopt(rsock, UdpGsoSegment, &(segment_size as _))
++                .expect("setsockopt UDP_SEGMENT failed");
++
++            bind(rsock, &sock_addr).unwrap();
++            let ssock = socket(
++                AddressFamily::Inet,
++                SockType::Datagram,
++                SockFlag::empty(),
++                None,
++            ).expect("send socket failed");
++
++            let mut num_packets_received: i32 = 0;
++
++            sendrecv(rsock, ssock, move |s, m, flags| {
++                let iov = [IoVec::from_slice(m)];
++                let cmsg = ControlMessage::UdpGsoSegments(&segment_size);
++                sendmsg(s, &iov, &[cmsg], flags, Some(&sock_addr))
++            }, {
++                let num_packets_received_ref = &mut num_packets_received;
++
++                move |len, _| {
++                    // check that we receive UDP packets with payload size
++                    // less or equal to segment size
++                    assert!(len <= segment_size as usize);
++                    *num_packets_received_ref += 1;
++                }
++            });
++
++            // Buffer size is 13, we will receive six packets of size 2,
++            // and one packet of size 1.
++            assert_eq!(7, num_packets_received);
++        }
++
++        #[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");
++
++            // It's hard to guarantee receiving GRO packets. Just checking
++            // that `setsockopt` doesn't fail with error
++
++            let rsock = socket(AddressFamily::Inet,
++                               SockType::Datagram,
++                               SockFlag::empty(),
++                               None
++            ).unwrap();
++
++            setsockopt(rsock, UdpGroSegment, &true)
++                .expect("setsockopt UDP_GRO failed");
++        }
++    }
++
++    #[cfg(any(
++        target_os = "linux",
++        target_os = "android",
++        target_os = "freebsd",
++        target_os = "netbsd",
++    ))]
++    #[test]
++    pub fn udp_sendmmsg() {
++        use nix::sys::uio::IoVec;
++
++        let std_sa = SocketAddr::from_str("127.0.0.1:6793").unwrap();
++        let std_sa2 = SocketAddr::from_str("127.0.0.1:6794").unwrap();
++        let inet_addr = InetAddr::from_std(&std_sa);
++        let inet_addr2 = InetAddr::from_std(&std_sa2);
++        let sock_addr = SockAddr::new_inet(inet_addr);
++        let sock_addr2 = SockAddr::new_inet(inet_addr2);
++
++        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 from = sendrecv(rsock, ssock, move |s, m, flags| {
++            let iov = [IoVec::from_slice(m)];
++            let mut msgs = Vec::new();
++            msgs.push(
++                SendMmsgData {
++                    iov: &iov,
++                    cmsgs: &[],
++                    addr: Some(sock_addr),
++                    _lt: Default::default(),
++                });
++
++            let batch_size = 15;
++
++            for _ in 0..batch_size {
++                msgs.push(
++                    SendMmsgData {
++                        iov: &iov,
++                        cmsgs: &[],
++                        addr: Some(sock_addr2),
++                        _lt: Default::default(),
++                    }
++                );
++            }
++            sendmmsg(s, msgs.iter(), flags)
++                .map(move |sent_bytes| {
++                    assert!(sent_bytes.len() >= 1);
++                    for sent in &sent_bytes {
++                        assert_eq!(*sent, m.len());
++                    }
++                    sent_bytes.len()
++                })
++        }, |_, _ | {});
++        // UDP sockets should set the from address
++        assert_eq!(AddressFamily::Inet, from.unwrap().family());
++    }
++
++    #[cfg(any(
++        target_os = "linux",
++        target_os = "android",
++        target_os = "freebsd",
++        target_os = "netbsd",
++    ))]
++    #[test]
++    pub fn udp_recvmmsg() {
++        use nix::sys::uio::IoVec;
++        use nix::sys::socket::{MsgFlags, recvmmsg};
++
++        const NUM_MESSAGES_SENT: usize = 2;
++        const DATA: [u8; 2] = [1,2];
++
++        let std_sa = SocketAddr::from_str("127.0.0.1:6798").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();
++            }
++        });
++
++        let mut msgs = std::collections::LinkedList::new();
++
++        // Buffers to receive exactly `NUM_MESSAGES_SENT` messages
++        let mut receive_buffers = [[0u8; 32]; NUM_MESSAGES_SENT];
++        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::empty(), None).expect("recvmmsg");
++        assert_eq!(res.len(), DATA.len());
++
++        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 {
++            assert_eq!(&buf[..DATA.len()], DATA);
++        }
++
++        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
+ #[test]
+ pub fn test_recvmsg_ebadf() {
+@@ -247,8 +599,13 @@ pub fn test_af_alg_cipher() {
+                            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
+@@ -311,6 +668,11 @@ pub fn test_af_alg_aead() {
+                            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);
++
+     let auth_size = 4usize;
+     let assoc_size = 16u32;
+ 
+@@ -383,6 +745,111 @@ pub fn test_af_alg_aead() {
+     assert_eq!(decrypted[(assoc_size as usize)..(payload_len + (assoc_size as usize))], payload[(assoc_size as usize)..payload_len + (assoc_size as usize)]);
+ }
+ 
++// Verify `ControlMessage::Ipv4PacketInfo` for `sendmsg`.
++// This creates a (udp) socket bound to localhost, then sends a message to
++// itself but uses Ipv4PacketInfo to force the source address to be localhost.
++//
++// This would be a more interesting test if we could assume that the test host
++// has more than one IP address (since we could select a different address to
++// test from).
++#[cfg(any(target_os = "linux",
++        target_os = "macos",
++        target_os = "netbsd"))]
++#[test]
++pub fn test_sendmsg_ipv4packetinfo() {
++    use nix::sys::uio::IoVec;
++    use nix::sys::socket::{socket, sendmsg, bind,
++                           AddressFamily, SockType, SockFlag, SockAddr,
++                           ControlMessage, MsgFlags};
++
++    let sock = socket(AddressFamily::Inet,
++                      SockType::Datagram,
++                      SockFlag::empty(),
++                      None)
++        .expect("socket failed");
++
++    let std_sa = SocketAddr::from_str("127.0.0.1:4000").unwrap();
++    let inet_addr = InetAddr::from_std(&std_sa);
++    let sock_addr = SockAddr::new_inet(inet_addr);
++
++    bind(sock, &sock_addr).expect("bind failed");
++
++    let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
++    let iov = [IoVec::from_slice(&slice)];
++
++    if let InetAddr::V4(sin) = inet_addr {
++        let pi = libc::in_pktinfo {
++            ipi_ifindex: 0, /* Unspecified interface */
++            ipi_addr: libc::in_addr { s_addr: 0 },
++            ipi_spec_dst: sin.sin_addr,
++        };
++
++        let cmsg = [ControlMessage::Ipv4PacketInfo(&pi)];
++
++        sendmsg(sock, &iov, &cmsg, MsgFlags::empty(), Some(&sock_addr))
++            .expect("sendmsg");
++    } else {
++        panic!("No IPv4 addresses available for testing?");
++    }
++}
++
++// Verify `ControlMessage::Ipv6PacketInfo` for `sendmsg`.
++// This creates a (udp) socket bound to ip6-localhost, then sends a message to
++// itself but uses Ipv6PacketInfo to force the source address to be
++// ip6-localhost.
++//
++// This would be a more interesting test if we could assume that the test host
++// has more than one IP address (since we could select a different address to
++// test from).
++#[cfg(any(target_os = "linux",
++        target_os = "macos",
++        target_os = "netbsd",
++        target_os = "freebsd"))]
++#[test]
++pub fn test_sendmsg_ipv6packetinfo() {
++    use nix::Error;
++    use nix::errno::Errno;
++    use nix::sys::uio::IoVec;
++    use nix::sys::socket::{socket, sendmsg, bind,
++                           AddressFamily, SockType, SockFlag, SockAddr,
++                           ControlMessage, MsgFlags};
++
++    let sock = socket(AddressFamily::Inet6,
++                      SockType::Datagram,
++                      SockFlag::empty(),
++                      None)
++        .expect("socket failed");
++
++    let std_sa = SocketAddr::from_str("[::1]:6000").unwrap();
++    let inet_addr = InetAddr::from_std(&std_sa);
++    let sock_addr = SockAddr::new_inet(inet_addr);
++
++    match bind(sock, &sock_addr) {
++        Err(Error::Sys(Errno::EADDRNOTAVAIL)) => {
++            println!("IPv6 not available, skipping test.");
++            return;
++        },
++        _ => (),
++    }
++
++    let slice = [1u8, 2, 3, 4, 5, 6, 7, 8];
++    let iov = [IoVec::from_slice(&slice)];
++
++    if let InetAddr::V6(sin) = inet_addr {
++        let pi = libc::in6_pktinfo {
++            ipi6_ifindex: 0, /* Unspecified interface */
++            ipi6_addr: sin.sin6_addr,
++        };
++
++        let cmsg = [ControlMessage::Ipv6PacketInfo(&pi)];
++
++        sendmsg(sock, &iov, &cmsg, MsgFlags::empty(), Some(&sock_addr))
++            .expect("sendmsg");
++    } else {
++        println!("No IPv6 addresses available for testing: skipping testing Ipv6PacketInfo");
++    }
++}
++
+ /// Tests that passing multiple fds using a single `ControlMessage` works.
+ // Disable the test on emulated platforms due to a bug in QEMU versions <
+ // 2.12.0.  https://bugs.launchpad.net/qemu/+bug/1701808
+@@ -468,29 +935,36 @@ pub fn test_sendmsg_empty_cmsgs() {
+     }
+ }
+ 
+-#[cfg(any(target_os = "android", target_os = "linux"))]
++#[cfg(any(
++    target_os = "android",
++    target_os = "linux",
++    target_os = "freebsd",
++    target_os = "dragonfly",
++))]
+ #[test]
+ fn test_scm_credentials() {
+-    use libc;
+     use nix::sys::uio::IoVec;
+     use nix::unistd::{close, getpid, getuid, getgid};
+-    use nix::sys::socket::{socketpair, sendmsg, recvmsg, setsockopt,
++    use nix::sys::socket::{socketpair, sendmsg, recvmsg,
+                            AddressFamily, SockType, SockFlag,
+-                           ControlMessage, ControlMessageOwned, MsgFlags};
+-    use nix::sys::socket::sockopt::PassCred;
++                           ControlMessage, ControlMessageOwned, MsgFlags,
++                           UnixCredentials};
++    #[cfg(any(target_os = "android", target_os = "linux"))]
++    use nix::sys::socket::{setsockopt, sockopt::PassCred};
+ 
+     let (send, recv) = socketpair(AddressFamily::Unix, SockType::Stream, None, SockFlag::empty())
+         .unwrap();
++    #[cfg(any(target_os = "android", target_os = "linux"))]
+     setsockopt(recv, PassCred, &true).unwrap();
+ 
+     {
+         let iov = [IoVec::from_slice(b"hello")];
+-        let cred = libc::ucred {
+-            pid: getpid().as_raw(),
+-            uid: getuid().as_raw(),
+-            gid: getgid().as_raw(),
+-        };
++        #[cfg(any(target_os = "android", target_os = "linux"))]
++        let cred = UnixCredentials::new();
++        #[cfg(any(target_os = "android", target_os = "linux"))]
+         let cmsg = ControlMessage::ScmCredentials(&cred);
++        #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++        let cmsg = ControlMessage::ScmCreds;
+         assert_eq!(sendmsg(send, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(), 5);
+         close(send).unwrap();
+     }
+@@ -498,20 +972,23 @@ fn test_scm_credentials() {
+     {
+         let mut buf = [0u8; 5];
+         let iov = [IoVec::from_mut_slice(&mut buf[..])];
+-        let mut cmsgspace = cmsg_space!(libc::ucred);
++        let mut cmsgspace = cmsg_space!(UnixCredentials);
+         let msg = recvmsg(recv, &iov, Some(&mut cmsgspace), MsgFlags::empty()).unwrap();
+         let mut received_cred = None;
+ 
+         for cmsg in msg.cmsgs() {
+-            if let ControlMessageOwned::ScmCredentials(cred) = cmsg {
+-                assert!(received_cred.is_none());
+-                assert_eq!(cred.pid, getpid().as_raw());
+-                assert_eq!(cred.uid, getuid().as_raw());
+-                assert_eq!(cred.gid, getgid().as_raw());
+-                received_cred = Some(cred);
+-            } else {
+-                panic!("unexpected cmsg");
+-            }
++            let cred = match cmsg {
++                #[cfg(any(target_os = "android", target_os = "linux"))]
++                ControlMessageOwned::ScmCredentials(cred) => cred,
++                #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
++                ControlMessageOwned::ScmCreds(cred) => cred,
++                other => panic!("unexpected cmsg {:?}", other),
++            };
++            assert!(received_cred.is_none());
++            assert_eq!(cred.pid(), getpid().as_raw());
++            assert_eq!(cred.uid(), getuid().as_raw());
++            assert_eq!(cred.gid(), getgid().as_raw());
++            received_cred = Some(cred);
+         }
+         received_cred.expect("no creds received");
+         assert_eq!(msg.bytes, 5);
+@@ -550,7 +1027,7 @@ fn test_too_large_cmsgspace() {
+ 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};
+@@ -569,7 +1046,7 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
+             pid: getpid().as_raw(),
+             uid: getuid().as_raw(),
+             gid: getgid().as_raw(),
+-        };
++        }.into();
+         let fds = [r];
+         let cmsgs = [
+             ControlMessage::ScmCredentials(&cred),
+@@ -597,9 +1074,9 @@ fn test_impl_scm_credentials_and_rights(mut space: Vec<u8>) {
+                 }
+                 ControlMessageOwned::ScmCredentials(cred) => {
+                     assert!(received_cred.is_none());
+-                    assert_eq!(cred.pid, getpid().as_raw());
+-                    assert_eq!(cred.uid, getuid().as_raw());
+-                    assert_eq!(cred.gid, getgid().as_raw());
++                    assert_eq!(cred.pid(), getpid().as_raw());
++                    assert_eq!(cred.uid(), getuid().as_raw());
++                    assert_eq!(cred.gid(), getgid().as_raw());
+                     received_cred = Some(cred);
+                 }
+                 _ => panic!("unexpected cmsg"),
+@@ -683,7 +1160,7 @@ pub fn test_syscontrol() {
+     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;
+@@ -1013,7 +1490,7 @@ pub fn test_recv_ipv6pktinfo() {
+     }
+ }
+ 
+-#[cfg(target_os = "linux")]
++#[cfg(any(target_os = "android", target_os = "linux"))]
+ #[test]
+ pub fn test_vsock() {
+     use libc;
+@@ -1030,17 +1507,11 @@ pub fn test_vsock() {
+                     SockFlag::empty(), None)
+              .expect("socket failed");
+ 
+-    // VMADDR_CID_HYPERVISOR and VMADDR_CID_RESERVED are reserved, so we expect
+-    // an EADDRNOTAVAIL error.
++    // VMADDR_CID_HYPERVISOR is reserved, so we expect an EADDRNOTAVAIL error.
+     let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_HYPERVISOR, port);
+     assert_eq!(bind(s1, &sockaddr).err(),
+                Some(Error::Sys(Errno::EADDRNOTAVAIL)));
+ 
+-    let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_RESERVED, port);
+-    assert_eq!(bind(s1, &sockaddr).err(),
+-               Some(Error::Sys(Errno::EADDRNOTAVAIL)));
+-
+-
+     let sockaddr = SockAddr::new_vsock(libc::VMADDR_CID_ANY, port);
+     assert_eq!(bind(s1, &sockaddr), Ok(()));
+     listen(s1, 10).expect("listen failed");
+diff --git a/third_party/rust/nix/test/sys/test_sockopt.rs b/third_party/rust/nix/test/sys/test_sockopt.rs
+index c4860c0d61d3d..56065931322ec 100644
+--- a/third_party/rust/nix/test/sys/test_sockopt.rs
++++ b/third_party/rust/nix/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]
+@@ -51,3 +53,44 @@ fn test_tcp_congestion() {
+         val
+     );
+ }
++
++#[test]
++#[cfg(any(target_os = "android", target_os = "linux"))]
++fn test_bindtodevice() {
++    skip_if_not_root!("test_bindtodevice");
++
++    let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
++
++    let val = getsockopt(fd, sockopt::BindToDevice).unwrap();
++    setsockopt(fd, sockopt::BindToDevice, &val).unwrap();
++
++    assert_eq!(
++        getsockopt(fd, sockopt::BindToDevice).unwrap(),
++        val
++    );
++}
++
++#[test]
++fn test_so_tcp_keepalive() {
++    let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), SockProtocol::Tcp).unwrap();
++    setsockopt(fd, sockopt::KeepAlive, &true).unwrap();
++    assert_eq!(getsockopt(fd, sockopt::KeepAlive).unwrap(), true);
++
++    #[cfg(any(target_os = "android",
++              target_os = "dragonfly",
++              target_os = "freebsd",
++              target_os = "linux",
++              target_os = "nacl"))] {
++        let x = getsockopt(fd, sockopt::TcpKeepIdle).unwrap();
++        setsockopt(fd, sockopt::TcpKeepIdle, &(x + 1)).unwrap();
++        assert_eq!(getsockopt(fd, sockopt::TcpKeepIdle).unwrap(), x + 1);
++
++        let x = getsockopt(fd, sockopt::TcpKeepCount).unwrap();
++        setsockopt(fd, sockopt::TcpKeepCount, &(x + 1)).unwrap();
++        assert_eq!(getsockopt(fd, sockopt::TcpKeepCount).unwrap(), x + 1);
++
++        let x = getsockopt(fd, sockopt::TcpKeepInterval).unwrap();
++        setsockopt(fd, sockopt::TcpKeepInterval, &(x + 1)).unwrap();
++        assert_eq!(getsockopt(fd, sockopt::TcpKeepInterval).unwrap(), x + 1);
++    }
++}
+diff --git a/third_party/rust/nix/test/sys/test_termios.rs b/third_party/rust/nix/test/sys/test_termios.rs
+index a14b8ce1a23cb..00aeb2fc57f15 100644
+--- a/third_party/rust/nix/test/sys/test_termios.rs
++++ b/third_party/rust/nix/test/sys/test_termios.rs
+@@ -4,7 +4,7 @@ use tempfile::tempfile;
+ use nix::{Error, fcntl};
+ use nix::errno::Errno;
+ use nix::pty::openpty;
+-use nix::sys::termios::{self, LocalFlags, OutputFlags, Termios, tcgetattr};
++use nix::sys::termios::{self, LocalFlags, OutputFlags, tcgetattr};
+ use nix::unistd::{read, write, close};
+ 
+ /// Helper function analogous to `std::io::Write::write_all`, but for `RawFd`s
+@@ -19,10 +19,10 @@ fn write_all(f: RawFd, buf: &[u8]) {
+ #[test]
+ fn test_tcgetattr_pty() {
+     // openpty uses ptname(3) internally
+-    let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+     let pty = openpty(None, None).expect("openpty failed");
+-    assert!(termios::tcgetattr(pty.master).is_ok());
++    assert!(termios::tcgetattr(pty.slave).is_ok());
+     close(pty.master).expect("closing the master failed");
+     close(pty.slave).expect("closing the slave failed");
+ }
+@@ -46,14 +46,14 @@ fn test_tcgetattr_ebadf() {
+ #[test]
+ fn test_output_flags() {
+     // openpty uses ptname(3) internally
+-    let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+     // Open one pty to get attributes for the second one
+     let mut termios = {
+         let pty = openpty(None, None).expect("openpty failed");
+         assert!(pty.master > 0);
+         assert!(pty.slave > 0);
+-        let termios = tcgetattr(pty.master).expect("tcgetattr failed");
++        let termios = tcgetattr(pty.slave).expect("tcgetattr failed");
+         close(pty.master).unwrap();
+         close(pty.slave).unwrap();
+         termios
+@@ -77,7 +77,7 @@ fn test_output_flags() {
+ 
+     // Read from the slave verifying that the output has been properly transformed
+     let mut buf = [0u8; 10];
+-    ::read_exact(pty.slave, &mut buf);
++    crate::read_exact(pty.slave, &mut buf);
+     let transformed_string = "foofoofoo\n";
+     close(pty.master).unwrap();
+     close(pty.slave).unwrap();
+@@ -88,14 +88,14 @@ fn test_output_flags() {
+ #[test]
+ fn test_local_flags() {
+     // openpty uses ptname(3) internally
+-    let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+     // Open one pty to get attributes for the second one
+     let mut termios = {
+         let pty = openpty(None, None).unwrap();
+         assert!(pty.master > 0);
+         assert!(pty.slave > 0);
+-        let termios = tcgetattr(pty.master).unwrap();
++        let termios = tcgetattr(pty.slave).unwrap();
+         close(pty.master).unwrap();
+         close(pty.slave).unwrap();
+         termios
+@@ -128,9 +128,3 @@ fn test_local_flags() {
+     close(pty.slave).unwrap();
+     assert_eq!(read, Error::Sys(Errno::EAGAIN));
+ }
+-
+-#[test]
+-fn test_cfmakeraw() {
+-    let mut termios = unsafe { Termios::default_uninit() };
+-    termios::cfmakeraw(&mut termios);
+-}
+diff --git a/third_party/rust/nix/test/sys/test_timerfd.rs b/third_party/rust/nix/test/sys/test_timerfd.rs
+new file mode 100644
+index 0000000000000..24fb2ac002e1d
+--- /dev/null
++++ b/third_party/rust/nix/test/sys/test_timerfd.rs
+@@ -0,0 +1,61 @@
++use nix::sys::time::{TimeSpec, TimeValLike};
++use nix::sys::timerfd::{ClockId, Expiration, TimerFd, TimerFlags, TimerSetTimeFlags};
++use std::time::Instant;
++
++#[test]
++pub fn test_timerfd_oneshot() {
++    let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap();
++
++    let before = Instant::now();
++
++    timer
++        .set(
++            Expiration::OneShot(TimeSpec::seconds(1)),
++            TimerSetTimeFlags::empty(),
++        )
++        .unwrap();
++
++    timer.wait().unwrap();
++
++    let millis = before.elapsed().as_millis();
++    assert!(millis > 900);
++}
++
++#[test]
++pub fn test_timerfd_interval() {
++    let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap();
++
++    let before = Instant::now();
++    timer
++        .set(
++            Expiration::IntervalDelayed(TimeSpec::seconds(1), TimeSpec::seconds(2)),
++            TimerSetTimeFlags::empty(),
++        )
++        .unwrap();
++
++    timer.wait().unwrap();
++
++    let start_delay = before.elapsed().as_millis();
++    assert!(start_delay > 900);
++
++    timer.wait().unwrap();
++
++    let interval_delay = before.elapsed().as_millis();
++    assert!(interval_delay > 2900);
++}
++
++#[test]
++pub fn test_timerfd_unset() {
++    let timer = TimerFd::new(ClockId::CLOCK_MONOTONIC, TimerFlags::empty()).unwrap();
++
++    timer
++        .set(
++            Expiration::OneShot(TimeSpec::seconds(1)),
++            TimerSetTimeFlags::empty(),
++        )
++        .unwrap();
++
++    timer.unset().unwrap();
++
++    assert!(timer.get().unwrap() == None);
++}
+diff --git a/third_party/rust/nix/test/sys/test_uio.rs b/third_party/rust/nix/test/sys/test_uio.rs
+index 3e4fc28ceb0e4..8d22bf1755a2c 100644
+--- a/third_party/rust/nix/test/sys/test_uio.rs
++++ b/third_party/rust/nix/test/sys/test_uio.rs
+@@ -6,7 +6,9 @@ use std::{cmp, iter};
+ use std::fs::{OpenOptions};
+ use std::os::unix::io::AsRawFd;
+ 
+-use tempfile::{tempfile, tempdir};
++#[cfg(not(target_os = "redox"))]
++use tempfile::tempfile;
++use tempfile::tempdir;
+ 
+ #[test]
+ fn test_writev() {
+@@ -53,6 +55,7 @@ fn test_writev() {
+ }
+ 
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_readv() {
+     let s:String = thread_rng().sample_iter(&Alphanumeric).take(128).collect();
+     let to_write = s.as_bytes().to_vec();
+@@ -97,6 +100,7 @@ fn test_readv() {
+ }
+ 
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_pwrite() {
+     use std::io::Read;
+ 
+@@ -199,15 +203,17 @@ fn test_process_vm_readv() {
+     use nix::unistd::ForkResult::*;
+     use nix::sys::signal::*;
+     use nix::sys::wait::*;
++    use crate::*;
+ 
+-    let _ = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++    require_capability!(CAP_SYS_PTRACE);
++    let _ = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+     // Pre-allocate memory in the child, since allocation isn't safe
+     // post-fork (~= async-signal-safe)
+     let mut vector = vec![1u8, 2, 3, 4, 5];
+ 
+     let (r, w) = pipe().unwrap();
+-    match fork().expect("Error: Fork Failed") {
++    match unsafe{fork()}.expect("Error: Fork Failed") {
+         Parent { child } => {
+             close(w).unwrap();
+             // wait for child
+diff --git a/third_party/rust/nix/test/sys/test_wait.rs b/third_party/rust/nix/test/sys/test_wait.rs
+index d07d82f0d9075..5bb298eba4d29 100644
+--- a/third_party/rust/nix/test/sys/test_wait.rs
++++ b/third_party/rust/nix/test/sys/test_wait.rs
+@@ -6,11 +6,12 @@ use nix::sys::wait::*;
+ use libc::_exit;
+ 
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_wait_signal() {
+-    let _ = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++    let _ = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+     // Safe: The child only calls `pause` and/or `_exit`, which are async-signal-safe.
+-    match fork().expect("Error: Fork Failed") {
++    match unsafe{fork()}.expect("Error: Fork Failed") {
+       Child => {
+           pause();
+           unsafe { _exit(123) }
+@@ -24,10 +25,10 @@ fn test_wait_signal() {
+ 
+ #[test]
+ fn test_wait_exit() {
+-    let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+     // Safe: Child only calls `_exit`, which is async-signal-safe.
+-    match fork().expect("Error: Fork Failed") {
++    match unsafe{fork()}.expect("Error: Fork Failed") {
+       Child => unsafe { _exit(12); },
+       Parent { child } => {
+           assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 12)));
+@@ -45,9 +46,9 @@ fn test_waitstatus_from_raw() {
+ 
+ #[test]
+ fn test_waitstatus_pid() {
+-    let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+-    match fork().unwrap() {
++    match unsafe{fork()}.unwrap() {
+         Child => unsafe { _exit(0) },
+         Parent { child } => {
+             let status = waitpid(child, None).unwrap();
+@@ -66,6 +67,7 @@ mod ptrace {
+     use nix::unistd::*;
+     use nix::unistd::ForkResult::*;
+     use libc::_exit;
++    use crate::*;
+ 
+     fn ptrace_child() -> ! {
+         ptrace::traceme().unwrap();
+@@ -82,7 +84,7 @@ mod ptrace {
+         assert!(ptrace::setoptions(child, Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT).is_ok());
+ 
+         // First, stop on the next system call, which will be exit()
+-        assert!(ptrace::syscall(child).is_ok());
++        assert!(ptrace::syscall(child, None).is_ok());
+         assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
+         // Then get the ptrace event for the process exiting
+         assert!(ptrace::cont(child, None).is_ok());
+@@ -94,9 +96,10 @@ mod ptrace {
+ 
+     #[test]
+     fn test_wait_ptrace() {
+-        let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++        require_capability!(CAP_SYS_PTRACE);
++        let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+-        match fork().expect("Error: Fork Failed") {
++        match unsafe{fork()}.expect("Error: Fork Failed") {
+             Child => ptrace_child(),
+             Parent { child } => ptrace_parent(child),
+         }
+diff --git a/third_party/rust/nix/test/test.rs b/third_party/rust/nix/test/test.rs
+index 6a71d261b5712..5a5330b7e4010 100644
+--- a/third_party/rust/nix/test/test.rs
++++ b/third_party/rust/nix/test/test.rs
+@@ -1,69 +1,13 @@
+-// XXX Allow deprecated items until release 0.16.0.  See issue #1096.
+-#![allow(deprecated)]
+-extern crate bytes;
+-#[cfg(any(target_os = "android", target_os = "linux"))]
+-extern crate caps;
+ #[macro_use]
+ extern crate cfg_if;
+-#[macro_use]
++#[cfg_attr(not(target_os = "redox"), macro_use)]
+ extern crate nix;
+ #[macro_use]
+ extern crate lazy_static;
+-extern crate libc;
+-extern crate rand;
+-#[cfg(target_os = "freebsd")]
+-extern crate sysctl;
+-extern crate tempfile;
+-
+-#[cfg(any(target_os = "android", target_os = "linux"))]
+-macro_rules! require_capability {
+-    ($capname:ident) => {
+-        use ::caps::{Capability, CapSet, has_cap};
+-        use ::std::io::{self, Write};
+-
+-        if !has_cap(None, CapSet::Effective, Capability::$capname).unwrap() {
+-            let stderr = io::stderr();
+-            let mut handle = stderr.lock();
+-            writeln!(handle, "Insufficient capabilities. Skipping test.")
+-                .unwrap();
+-            return;
+-        }
+-    }
+-}
+-
+-#[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()
+-        {
+-            use ::std::io::Write;
+-            let stderr = ::std::io::stderr();
+-            let mut handle = stderr.lock();
+-            writeln!(handle, "{} cannot run in a jail. Skipping test.", $name)
+-                .unwrap();
+-            return;
+-        }
+-    }
+-}
+-
+-macro_rules! skip_if_not_root {
+-    ($name:expr) => {
+-        use nix::unistd::Uid;
+-
+-        if !Uid::current().is_root() {
+-            use ::std::io::Write;
+-            let stderr = ::std::io::stderr();
+-            let mut handle = stderr.lock();
+-            writeln!(handle, "{} requires root privileges. Skipping test.", $name).unwrap();
+-            return;
+-        }
+-    };
+-}
+ 
++mod common;
+ mod sys;
++#[cfg(not(target_os = "redox"))]
+ mod test_dir;
+ mod test_fcntl;
+ #[cfg(any(target_os = "android",
+@@ -75,10 +19,15 @@ mod test_kmod;
+           target_os = "linux",
+           target_os = "netbsd"))]
+ mod test_mq;
++#[cfg(not(target_os = "redox"))]
+ mod test_net;
+ mod test_nix_path;
+ mod test_poll;
++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
+ mod test_pty;
++#[cfg(any(target_os = "android",
++          target_os = "linux"))]
++mod test_sched;
+ #[cfg(any(target_os = "android",
+           target_os = "freebsd",
+           target_os = "ios",
+@@ -86,6 +35,7 @@ mod test_pty;
+           target_os = "macos"))]
+ mod test_sendfile;
+ mod test_stat;
++mod test_time;
+ mod test_unistd;
+ 
+ use std::os::unix::io::RawFd;
+@@ -93,6 +43,7 @@ use std::path::PathBuf;
+ 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;
+@@ -130,7 +81,7 @@ struct DirRestore<'a> {
+ 
+ impl<'a> DirRestore<'a> {
+     fn new() -> Self {
+-        let guard = ::CWD_LOCK.write()
++        let guard = crate::CWD_LOCK.write()
+             .expect("Lock got poisoned by another test");
+         DirRestore{
+             _g: guard,
+diff --git a/third_party/rust/nix/test/test_clearenv.rs b/third_party/rust/nix/test/test_clearenv.rs
+new file mode 100644
+index 0000000000000..28a77680498ca
+--- /dev/null
++++ b/third_party/rust/nix/test/test_clearenv.rs
+@@ -0,0 +1,9 @@
++use std::env;
++
++#[test]
++fn clearenv() {
++    env::set_var("FOO", "BAR");
++    unsafe { nix::env::clearenv() }.unwrap();
++    assert_eq!(env::var("FOO").unwrap_err(), env::VarError::NotPresent);
++    assert_eq!(env::vars().count(), 0);
++}
+diff --git a/third_party/rust/nix/test/test_dir.rs b/third_party/rust/nix/test/test_dir.rs
+index c42fbcd18a29d..505277e7143b7 100644
+--- a/third_party/rust/nix/test/test_dir.rs
++++ b/third_party/rust/nix/test/test_dir.rs
+@@ -1,11 +1,8 @@
+-extern crate nix;
+-extern crate tempfile;
+-
+ use nix::dir::{Dir, Type};
+ use nix::fcntl::OFlag;
+ use nix::sys::stat::Mode;
+ use std::fs::File;
+-use self::tempfile::tempdir;
++use tempfile::tempdir;
+ 
+ #[test]
+ fn read() {
+@@ -37,7 +34,9 @@ fn rewind() {
+                             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/third_party/rust/nix/test/test_fcntl.rs b/third_party/rust/nix/test/test_fcntl.rs
+index 6b2bbd679fc31..5d1bafebe195f 100644
+--- a/third_party/rust/nix/test/test_fcntl.rs
++++ b/third_party/rust/nix/test/test_fcntl.rs
+@@ -1,14 +1,28 @@
++#[cfg(not(target_os = "redox"))]
+ use nix::Error;
++#[cfg(not(target_os = "redox"))]
+ use nix::errno::*;
+-use nix::fcntl::{openat, open, OFlag, readlink, readlinkat, renameat};
++#[cfg(not(target_os = "redox"))]
++use nix::fcntl::{open, OFlag, readlink};
++#[cfg(not(target_os = "redox"))]
++use nix::fcntl::{openat, readlinkat, renameat};
++#[cfg(not(target_os = "redox"))]
+ use nix::sys::stat::Mode;
++#[cfg(not(target_os = "redox"))]
+ use nix::unistd::{close, read};
++#[cfg(not(target_os = "redox"))]
+ use tempfile::{self, NamedTempFile};
++#[cfg(not(target_os = "redox"))]
+ use std::fs::File;
++#[cfg(not(target_os = "redox"))]
+ use std::io::prelude::*;
++#[cfg(not(target_os = "redox"))]
+ use std::os::unix::fs;
+ 
++use crate::*;
++
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_openat() {
+     const CONTENTS: &[u8] = b"abcd";
+     let mut tmp = NamedTempFile::new().unwrap();
+@@ -31,6 +45,7 @@ fn test_openat() {
+ }
+ 
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_renameat() {
+     let old_dir = tempfile::tempdir().unwrap();
+     let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
+@@ -47,6 +62,7 @@ fn test_renameat() {
+ }
+ 
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_readlink() {
+     let tempdir = tempfile::tempdir().unwrap();
+     let src = tempdir.path().join("a");
+@@ -56,28 +72,31 @@ fn test_readlink() {
+     let dirfd = open(tempdir.path(),
+                      OFlag::empty(),
+                      Mode::empty()).unwrap();
++    let expected_dir = src.to_str().unwrap();
++
++    assert_eq!(readlink(&dst).unwrap().to_str().unwrap(), expected_dir);
++    assert_eq!(readlinkat(dirfd, "b").unwrap().to_str().unwrap(), expected_dir);
+ 
+-    let mut buf = vec![0; src.to_str().unwrap().len() + 1];
+-    assert_eq!(readlink(&dst, &mut buf).unwrap().to_str().unwrap(),
+-               src.to_str().unwrap());
+-    assert_eq!(readlinkat(dirfd, "b", &mut buf).unwrap().to_str().unwrap(),
+-               src.to_str().unwrap());
+ }
+ 
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ mod linux_android {
++    use std::fs::File;
+     use std::io::prelude::*;
+-    use std::io::SeekFrom;
++    use std::io::{BufRead, BufReader, SeekFrom};
+     use std::os::unix::prelude::*;
+ 
+     use libc::loff_t;
+ 
+     use nix::fcntl::*;
++    use nix::sys::stat::fstat;
+     use nix::sys::uio::IoVec;
+     use nix::unistd::{close, pipe, read, write};
+ 
+     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
+@@ -198,6 +217,113 @@ mod linux_android {
+         let mut buf = [0u8; 200];
+         assert_eq!(100, read(fd, &mut buf).unwrap());
+     }
++
++    // The tests below are disabled for the listed targets
++    // due to OFD locks not being available in the kernel/libc
++    // versions used in the CI environment, probably because
++    // they run under QEMU.
++
++    #[test]
++    #[cfg(not(any(target_arch = "aarch64",
++                  target_arch = "arm",
++                  target_arch = "armv7",
++                  target_arch = "x86",
++                  target_arch = "mips",
++                  target_arch = "mips64",
++                  target_arch = "mips64el",
++                  target_arch = "powerpc64",
++                  target_arch = "powerpc64le",
++                  target_env = "musl")))]
++    fn test_ofd_write_lock() {
++        let tmp = NamedTempFile::new().unwrap();
++
++        let fd = tmp.as_raw_fd();
++        let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap();
++        if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC {
++            // OverlayFS is a union file system.  It returns one inode value in
++            // stat(2), but a different one shows up in /proc/locks.  So we must
++            // skip the test.
++            skip!("/proc/locks does not work on overlayfs");
++        }
++        let inode = fstat(fd).expect("fstat failed").st_ino as usize;
++
++        let mut flock = libc::flock {
++            l_type: libc::F_WRLCK as libc::c_short,
++            l_whence: libc::SEEK_SET as libc::c_short,
++            l_start: 0,
++            l_len: 0,
++            l_pid: 0,
++        };
++        fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write lock failed");
++        assert_eq!(
++            Some(("OFDLCK".to_string(), "WRITE".to_string())),
++            lock_info(inode)
++        );
++
++        flock.l_type = libc::F_UNLCK as libc::c_short;
++        fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("write unlock failed");
++        assert_eq!(None, lock_info(inode));
++    }
++
++    #[test]
++    #[cfg(not(any(target_arch = "aarch64",
++                  target_arch = "arm",
++                  target_arch = "armv7",
++                  target_arch = "x86",
++                  target_arch = "mips",
++                  target_arch = "mips64",
++                  target_arch = "mips64el",
++                  target_arch = "powerpc64",
++                  target_arch = "powerpc64le",
++                  target_env = "musl")))]
++    fn test_ofd_read_lock() {
++        let tmp = NamedTempFile::new().unwrap();
++
++        let fd = tmp.as_raw_fd();
++        let statfs = nix::sys::statfs::fstatfs(&tmp).unwrap();
++        if statfs.filesystem_type() == nix::sys::statfs::OVERLAYFS_SUPER_MAGIC {
++            // OverlayFS is a union file system.  It returns one inode value in
++            // stat(2), but a different one shows up in /proc/locks.  So we must
++            // skip the test.
++            skip!("/proc/locks does not work on overlayfs");
++        }
++        let inode = fstat(fd).expect("fstat failed").st_ino as usize;
++
++        let mut flock = libc::flock {
++            l_type: libc::F_RDLCK as libc::c_short,
++            l_whence: libc::SEEK_SET as libc::c_short,
++            l_start: 0,
++            l_len: 0,
++            l_pid: 0,
++        };
++        fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read lock failed");
++        assert_eq!(
++            Some(("OFDLCK".to_string(), "READ".to_string())),
++            lock_info(inode)
++        );
++
++        flock.l_type = libc::F_UNLCK as libc::c_short;
++        fcntl(fd, FcntlArg::F_OFD_SETLKW(&flock)).expect("read unlock failed");
++        assert_eq!(None, lock_info(inode));
++    }
++
++    fn lock_info(inode: usize) -> Option<(String, String)> {
++        let file = File::open("/proc/locks").expect("open /proc/locks failed");
++        let buf = BufReader::new(file);
++
++        for line in buf.lines() {
++            let line = line.unwrap();
++            let parts: Vec<_> = line.split_whitespace().collect();
++            let lock_type = parts[1];
++            let lock_access = parts[3];
++            let ino_parts: Vec<_> = parts[5].split(':').collect();
++            let ino: usize = ino_parts[2].parse().unwrap();
++            if ino == inode {
++                return Some((lock_type.to_string(), lock_access.to_string()));
++            }
++        }
++        None
++    }
+ }
+ 
+ #[cfg(any(target_os = "linux",
+@@ -206,7 +332,7 @@ mod linux_android {
+           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;
+@@ -232,3 +358,60 @@ mod test_posix_fadvise {
+         assert_eq!(errno, Errno::ESPIPE as i32);
+     }
+ }
++
++#[cfg(any(target_os = "linux",
++          target_os = "android",
++          target_os = "emscripten",
++          target_os = "fuchsia",
++          any(target_os = "wasi", target_env = "wasi"),
++          target_os = "freebsd"))]
++mod test_posix_fallocate {
++
++    use tempfile::NamedTempFile;
++    use std::{io::Read, os::unix::io::{RawFd, AsRawFd}};
++    use nix::errno::Errno;
++    use nix::fcntl::*;
++    use nix::unistd::pipe;
++
++    #[test]
++    fn success() {
++        const LEN: usize = 100;
++        let mut tmp = NamedTempFile::new().unwrap();
++        let fd = tmp.as_raw_fd();
++        let res = posix_fallocate(fd, 0, LEN as libc::off_t);
++        match res {
++            Ok(_) => {
++                let mut data = [1u8; LEN];
++                assert_eq!(tmp.read(&mut data).expect("read failure"), LEN);
++                assert_eq!(&data[..], &[0u8; LEN][..]);
++            }
++            Err(nix::Error::Sys(Errno::EINVAL)) => {
++                // POSIX requires posix_fallocate to return EINVAL both for
++                // invalid arguments (i.e. len < 0) and if the operation is not
++                // supported by the file system.
++                // There's no way to tell for sure whether the file system
++                // supports posix_fallocate, so we must pass the test if it
++                // returns EINVAL.
++            }
++            _ => res.unwrap(),
++        }
++    }
++
++    #[test]
++    fn errno() {
++        let (rd, _wr) = pipe().unwrap();
++        let err = posix_fallocate(rd as RawFd, 0, 100).unwrap_err();
++        use nix::Error::Sys;
++        match err {
++            Sys(Errno::EINVAL)
++                | Sys(Errno::ENODEV)
++                | Sys(Errno::ESPIPE)
++                | Sys(Errno::EBADF) => (),
++            errno =>
++                panic!(
++                    "unexpected errno {}",
++                    errno,
++                ),
++        }
++    }
++}
+diff --git a/third_party/rust/nix/test/test_kmod/mod.rs b/third_party/rust/nix/test/test_kmod/mod.rs
+index ad406357b06d2..fb7260ba9c9d9 100644
+--- a/third_party/rust/nix/test/test_kmod/mod.rs
++++ b/third_party/rust/nix/test/test_kmod/mod.rs
+@@ -2,9 +2,10 @@ use std::fs::copy;
+ use std::path::PathBuf;
+ use std::process::Command;
+ use tempfile::{tempdir, TempDir};
++use crate::*;
+ 
+ fn compile_kernel_module() -> (PathBuf, String, TempDir) {
+-    let _m = ::FORK_MTX
++    let _m = crate::FORK_MTX
+         .lock()
+         .expect("Mutex got poisoned by another test");
+ 
+@@ -41,8 +42,8 @@ use std::io::Read;
+ #[test]
+ fn test_finit_and_delete_module() {
+     require_capability!(CAP_SYS_MODULE);
+-    let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
+-    let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++    let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
+ 
+     let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
+ 
+@@ -59,8 +60,8 @@ fn test_finit_and_delete_module() {
+ #[test]
+ fn test_finit_and_delete_modul_with_params() {
+     require_capability!(CAP_SYS_MODULE);
+-    let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
+-    let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++    let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
+ 
+     let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
+ 
+@@ -80,8 +81,8 @@ fn test_finit_and_delete_modul_with_params() {
+ #[test]
+ fn test_init_and_delete_module() {
+     require_capability!(CAP_SYS_MODULE);
+-    let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
+-    let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++    let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
+ 
+     let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
+ 
+@@ -100,8 +101,8 @@ fn test_init_and_delete_module() {
+ #[test]
+ fn test_init_and_delete_module_with_params() {
+     require_capability!(CAP_SYS_MODULE);
+-    let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
+-    let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++    let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
+ 
+     let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
+ 
+@@ -121,8 +122,8 @@ fn test_init_and_delete_module_with_params() {
+ #[test]
+ fn test_finit_module_invalid() {
+     require_capability!(CAP_SYS_MODULE);
+-    let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
+-    let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++    let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
+ 
+     let kmod_path = "/dev/zero";
+ 
+@@ -135,8 +136,8 @@ fn test_finit_module_invalid() {
+ #[test]
+ fn test_finit_module_twice_and_delete_module() {
+     require_capability!(CAP_SYS_MODULE);
+-    let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
+-    let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++    let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
+ 
+     let (kmod_path, kmod_name, _kmod_dir) = compile_kernel_module();
+ 
+@@ -157,8 +158,8 @@ fn test_finit_module_twice_and_delete_module() {
+ #[test]
+ fn test_delete_module_not_loaded() {
+     require_capability!(CAP_SYS_MODULE);
+-    let _m0 = ::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
+-    let _m1 = ::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++    let _m0 = crate::KMOD_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m1 = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
+ 
+     let result = delete_module(&CString::new("hello").unwrap(), DeleteModuleFlags::empty());
+ 
+diff --git a/third_party/rust/nix/test/test_mount.rs b/third_party/rust/nix/test/test_mount.rs
+index d2e08bc42855d..c1b6c8a3bf2d2 100644
+--- a/third_party/rust/nix/test/test_mount.rs
++++ b/third_party/rust/nix/test/test_mount.rs
+@@ -1,12 +1,10 @@
++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
+ // without root.
+ 
+-extern crate libc;
+-extern crate nix;
+-extern crate tempfile;
+-
+ #[cfg(target_os = "linux")]
+ mod test_mount {
+     use std::fs::{self, File};
+@@ -226,6 +224,7 @@ fn main() {
+     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/third_party/rust/nix/test/test_mq.rs b/third_party/rust/nix/test/test_mq.rs
+index caac4fc261cd6..1667a35b1a04b 100644
+--- a/third_party/rust/nix/test/test_mq.rs
++++ b/third_party/rust/nix/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();
+ 
+@@ -31,7 +29,7 @@ fn test_mq_send_and_receive() {
+     let mut buf = [0u8; 32];
+     let mut prio = 0u32;
+     let len = mq_receive(mqd1, &mut buf, &mut prio).unwrap();
+-    assert!(prio == 1);
++    assert_eq!(prio, 1);
+ 
+     mq_close(mqd1).unwrap();
+     mq_close(mqd0).unwrap();
+@@ -43,7 +41,7 @@ fn test_mq_send_and_receive() {
+ #[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 @@ fn test_mq_getattr() {
+ #[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 @@ fn test_mq_setattr() {
+     // 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 @@ fn test_mq_setattr() {
+ #[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,10 +114,10 @@ fn test_mq_set_nonblocking() {
+     let mqd = r.unwrap();
+     mq_set_nonblock(mqd).unwrap();
+     let new_attr = mq_getattr(mqd);
+-    assert!(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!(new_attr.unwrap().flags() == 0);
++    assert_eq!(new_attr.unwrap().flags(), 0);
+     mq_close(mqd).unwrap();
+ }
+ 
+@@ -127,7 +125,7 @@ fn test_mq_set_nonblocking() {
+ #[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();
+@@ -141,12 +139,12 @@ fn test_mq_unlink() {
+     let mqd = r.unwrap();
+ 
+     let res_unlink = mq_unlink(mq_name_opened);
+-    assert!(res_unlink == Ok(()) );
++    assert_eq!(res_unlink, Ok(()) );
+ 
+     let res_unlink_not_opened = mq_unlink(mq_name_not_opened);
+-    assert!(res_unlink_not_opened == Err(Sys(ENOENT)) );
++    assert_eq!(res_unlink_not_opened, Err(Sys(ENOENT)) );
+ 
+     mq_close(mqd).unwrap();
+     let res_unlink_after_close = mq_unlink(mq_name_opened);
+-    assert!(res_unlink_after_close == Err(Sys(ENOENT)) );
++    assert_eq!(res_unlink_after_close, Err(Sys(ENOENT)) );
+ }
+diff --git a/third_party/rust/nix/test/test_poll.rs b/third_party/rust/nix/test/test_poll.rs
+index aef40e4792b5a..acfaad8bea6c0 100644
+--- a/third_party/rust/nix/test/test_poll.rs
++++ b/third_party/rust/nix/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 @@ fn test_poll() {
+     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,14 +53,15 @@ fn test_ppoll() {
+     let mut fds = [PollFd::new(r, PollFlags::POLLIN)];
+ 
+     // Poll an idle pipe.  Should timeout
+-    let nfds = ppoll(&mut fds, 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));
+ 
+     write(w, b".").unwrap();
+ 
+     // Poll a readable pipe.  Should return an event.
+-    let nfds = ppoll(&mut fds, timeout, SigSet::empty()).unwrap();
++    let nfds = ppoll(&mut fds, Some(timeout), SigSet::empty()).unwrap();
+     assert_eq!(nfds, 1);
+     assert!(fds[0].revents().unwrap().contains(PollFlags::POLLIN));
+ }
+diff --git a/third_party/rust/nix/test/test_pty.rs b/third_party/rust/nix/test/test_pty.rs
+index 476b15c10128c..ab347bb040f5f 100644
+--- a/third_party/rust/nix/test/test_pty.rs
++++ b/third_party/rust/nix/test/test_pty.rs
+@@ -1,4 +1,5 @@
+-use std::io::Write;
++use std::fs::File;
++use std::io::{Read, Write};
+ use std::path::Path;
+ use std::os::unix::prelude::*;
+ use tempfile::tempfile;
+@@ -28,7 +29,7 @@ fn test_explicit_close() {
+ #[test]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ fn test_ptsname_equivalence() {
+-    let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+     // Open a new PTTY master
+     let master_fd = posix_openpt(OFlag::O_RDWR).unwrap();
+@@ -45,7 +46,7 @@ fn test_ptsname_equivalence() {
+ #[test]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ fn test_ptsname_copy() {
+-    let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+     // Open a new PTTY master
+     let master_fd = posix_openpt(OFlag::O_RDWR).unwrap();
+@@ -54,7 +55,7 @@ fn test_ptsname_copy() {
+     // Get the name of the slave
+     let slave_name1 = unsafe { ptsname(&master_fd) }.unwrap();
+     let slave_name2 = unsafe { ptsname(&master_fd) }.unwrap();
+-    assert!(slave_name1 == slave_name2);
++    assert_eq!(slave_name1, slave_name2);
+     // Also make sure that the string was actually copied and they point to different parts of
+     // memory.
+     assert!(slave_name1.as_ptr() != slave_name2.as_ptr());
+@@ -71,7 +72,7 @@ fn test_ptsname_r_copy() {
+     // Get the name of the slave
+     let slave_name1 = ptsname_r(&master_fd).unwrap();
+     let slave_name2 = ptsname_r(&master_fd).unwrap();
+-    assert!(slave_name1 == slave_name2);
++    assert_eq!(slave_name1, slave_name2);
+     assert!(slave_name1.as_ptr() != slave_name2.as_ptr());
+ }
+ 
+@@ -79,7 +80,7 @@ fn test_ptsname_r_copy() {
+ #[test]
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ fn test_ptsname_unique() {
+-    let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+     // Open a new PTTY master
+     let master1_fd = posix_openpt(OFlag::O_RDWR).unwrap();
+@@ -95,35 +96,74 @@ fn test_ptsname_unique() {
+     assert!(slave_name1 != slave_name2);
+ }
+ 
+-/// Test opening a master/slave PTTY pair
+-///
+-/// This is a single larger test because much of these functions aren't useful by themselves. So for
+-/// this test we perform the basic act of getting a file handle for a connect master/slave PTTY
+-/// pair.
+-#[test]
+-fn test_open_ptty_pair() {
+-    let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++/// Common setup for testing PTTY pairs
++fn open_ptty_pair() -> (PtyMaster, File) {
++    let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+     // Open a new PTTY master
+-    let master_fd = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed");
+-    assert!(master_fd.as_raw_fd() > 0);
++    let master = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed");
+ 
+     // Allow a slave to be generated for it
+-    grantpt(&master_fd).expect("grantpt failed");
+-    unlockpt(&master_fd).expect("unlockpt failed");
++    grantpt(&master).expect("grantpt failed");
++    unlockpt(&master).expect("unlockpt failed");
+ 
+     // Get the name of the slave
+-    let slave_name = unsafe { ptsname(&master_fd) }.expect("ptsname failed");
++    let slave_name = unsafe { ptsname(&master) }.expect("ptsname failed");
+ 
+     // Open the slave device
+     let slave_fd = open(Path::new(&slave_name), OFlag::O_RDWR, stat::Mode::empty()).unwrap();
+-    assert!(slave_fd > 0);
++    let slave = unsafe { File::from_raw_fd(slave_fd) };
++
++    (master, slave)
++}
++
++/// Test opening a master/slave PTTY pair
++///
++/// This uses a common `open_ptty_pair` because much of these functions aren't useful by
++/// themselves. So for this test we perform the basic act of getting a file handle for a
++/// master/slave PTTY pair, then just sanity-check the raw values.
++#[test]
++fn test_open_ptty_pair() {
++    let (master, slave) = open_ptty_pair();
++    assert!(master.as_raw_fd() > 0);
++    assert!(slave.as_raw_fd() > 0);
++}
++
++/// Put the terminal in raw mode.
++fn make_raw(fd: RawFd) {
++    let mut termios = tcgetattr(fd).unwrap();
++    cfmakeraw(&mut termios);
++    tcsetattr(fd, SetArg::TCSANOW, &termios).unwrap();
++}
++
++/// Test `io::Read` on the PTTY master
++#[test]
++fn test_read_ptty_pair() {
++    let (mut master, mut slave) = open_ptty_pair();
++    make_raw(slave.as_raw_fd());
++
++    let mut buf = [0u8; 5];
++    slave.write_all(b"hello").unwrap();
++    master.read_exact(&mut buf).unwrap();
++    assert_eq!(&buf, b"hello");
++}
++
++/// Test `io::Write` on the PTTY master
++#[test]
++fn test_write_ptty_pair() {
++    let (mut master, mut slave) = open_ptty_pair();
++    make_raw(slave.as_raw_fd());
++
++    let mut buf = [0u8; 5];
++    master.write_all(b"adios").unwrap();
++    slave.read_exact(&mut buf).unwrap();
++    assert_eq!(&buf, b"adios");
+ }
+ 
+ #[test]
+ fn test_openpty() {
+     // openpty uses ptname(3) internally
+-    let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+     let pty = openpty(None, None).unwrap();
+     assert!(pty.master > 0);
+@@ -133,21 +173,21 @@ fn test_openpty() {
+     let string = "foofoofoo\n";
+     let mut buf = [0u8; 10];
+     write(pty.master, string.as_bytes()).unwrap();
+-    ::read_exact(pty.slave, &mut buf);
++    crate::read_exact(pty.slave, &mut buf);
+ 
+     assert_eq!(&buf, string.as_bytes());
+ 
+     // Read the echo as well
+     let echoed_string = "foofoofoo\r\n";
+     let mut buf = [0u8; 11];
+-    ::read_exact(pty.master, &mut buf);
++    crate::read_exact(pty.master, &mut buf);
+     assert_eq!(&buf, echoed_string.as_bytes());
+ 
+     let string2 = "barbarbarbar\n";
+     let echoed_string2 = "barbarbarbar\r\n";
+     let mut buf = [0u8; 14];
+     write(pty.slave, string2.as_bytes()).unwrap();
+-    ::read_exact(pty.master, &mut buf);
++    crate::read_exact(pty.master, &mut buf);
+ 
+     assert_eq!(&buf, echoed_string2.as_bytes());
+ 
+@@ -158,14 +198,14 @@ fn test_openpty() {
+ #[test]
+ fn test_openpty_with_termios() {
+     // openpty uses ptname(3) internally
+-    let _m = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+     // Open one pty to get attributes for the second one
+     let mut termios = {
+         let pty = openpty(None, None).unwrap();
+         assert!(pty.master > 0);
+         assert!(pty.slave > 0);
+-        let termios = tcgetattr(pty.master).unwrap();
++        let termios = tcgetattr(pty.slave).unwrap();
+         close(pty.master).unwrap();
+         close(pty.slave).unwrap();
+         termios
+@@ -182,20 +222,20 @@ fn test_openpty_with_termios() {
+     let string = "foofoofoo\n";
+     let mut buf = [0u8; 10];
+     write(pty.master, string.as_bytes()).unwrap();
+-    ::read_exact(pty.slave, &mut buf);
++    crate::read_exact(pty.slave, &mut buf);
+ 
+     assert_eq!(&buf, string.as_bytes());
+ 
+     // read the echo as well
+     let echoed_string = "foofoofoo\n";
+-    ::read_exact(pty.master, &mut buf);
++    crate::read_exact(pty.master, &mut buf);
+     assert_eq!(&buf, echoed_string.as_bytes());
+ 
+     let string2 = "barbarbarbar\n";
+     let echoed_string2 = "barbarbarbar\n";
+     let mut buf = [0u8; 13];
+     write(pty.slave, string2.as_bytes()).unwrap();
+-    ::read_exact(pty.master, &mut buf);
++    crate::read_exact(pty.master, &mut buf);
+ 
+     assert_eq!(&buf, echoed_string2.as_bytes());
+ 
+@@ -209,9 +249,9 @@ fn test_forkpty() {
+     use nix::sys::signal::*;
+     use nix::sys::wait::wait;
+     // forkpty calls openpty which uses ptname(3) internally.
+-    let _m0 = ::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m0 = crate::PTSNAME_MTX.lock().expect("Mutex got poisoned by another test");
+     // forkpty spawns a child process
+-    let _m1 = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m1 = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+     let string = "naninani\n";
+     let echoed_string = "naninani\r\n";
+@@ -225,7 +265,7 @@ fn test_forkpty() {
+         Parent { child } => {
+             let mut buf = [0u8; 10];
+             assert!(child.as_raw() > 0);
+-            ::read_exact(pty.master, &mut buf);
++            crate::read_exact(pty.master, &mut buf);
+             kill(child, SIGTERM).unwrap();
+             wait().unwrap(); // keep other tests using generic wait from getting our child
+             assert_eq!(&buf, echoed_string.as_bytes());
+diff --git a/third_party/rust/nix/test/test_ptymaster_drop.rs b/third_party/rust/nix/test/test_ptymaster_drop.rs
+index 9b59d66435ed0..ff939b9c63e76 100644
+--- a/third_party/rust/nix/test/test_ptymaster_drop.rs
++++ b/third_party/rust/nix/test/test_ptymaster_drop.rs
+@@ -1,21 +1,24 @@
+-extern crate nix;
++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
++mod t {
++    use nix::fcntl::OFlag;
++    use nix::pty::*;
++    use nix::unistd::close;
++    use std::os::unix::io::AsRawFd;
+ 
+-use nix::fcntl::OFlag;
+-use nix::pty::*;
+-use nix::unistd::close;
+-use std::os::unix::io::AsRawFd;
+-
+-/// Regression test for Issue #659
+-/// `PtyMaster` should panic rather than double close the file descriptor
+-/// This must run in its own test process because it deliberately creates a race
+-/// condition.
+-#[test]
+-#[should_panic(expected = "Closing an invalid file descriptor!")]
+-// In Travis on i686-unknown-linux-musl, this test gets SIGABRT.  I don't know
+-// why.  It doesn't happen on any other target, and it doesn't happen on my PC.
+-#[cfg_attr(all(target_env = "musl", target_arch = "x86"), ignore)]
+-fn test_double_close() {
+-    let m = posix_openpt(OFlag::O_RDWR).unwrap();
+-    close(m.as_raw_fd()).unwrap();
+-    drop(m);            // should panic here
++    /// Regression test for Issue #659
++    ///
++    /// `PtyMaster` should panic rather than double close the file descriptor
++    /// This must run in its own test process because it deliberately creates a
++    /// race condition.
++    #[test]
++    #[should_panic(expected = "Closing an invalid file descriptor!")]
++    // In Travis on i686-unknown-linux-musl, this test gets SIGABRT.  I don't
++    // know why.  It doesn't happen on any other target, and it doesn't happen
++    // on my PC.
++    #[cfg_attr(all(target_env = "musl", target_arch = "x86"), ignore)]
++    fn test_double_close() {
++        let m = posix_openpt(OFlag::O_RDWR).unwrap();
++        close(m.as_raw_fd()).unwrap();
++        drop(m);            // should panic here
++    }
+ }
+diff --git a/third_party/rust/nix/test/test_sched.rs b/third_party/rust/nix/test/test_sched.rs
+new file mode 100644
+index 0000000000000..922196a3dba73
+--- /dev/null
++++ b/third_party/rust/nix/test/test_sched.rs
+@@ -0,0 +1,32 @@
++use nix::sched::{sched_getaffinity, sched_setaffinity, CpuSet};
++use nix::unistd::Pid;
++
++#[test]
++fn test_sched_affinity() {
++    // If pid is zero, then the mask of the calling process is returned.
++    let initial_affinity = sched_getaffinity(Pid::from_raw(0)).unwrap();
++    let mut at_least_one_cpu = false;
++    let mut last_valid_cpu = 0;
++    for field in 0..CpuSet::count() {
++        if initial_affinity.is_set(field).unwrap() {
++            at_least_one_cpu = true;
++            last_valid_cpu = field;
++        }
++    }
++    assert!(at_least_one_cpu);
++
++    // Now restrict the running CPU
++    let mut new_affinity = CpuSet::new();
++    new_affinity.set(last_valid_cpu).unwrap();
++    sched_setaffinity(Pid::from_raw(0), &new_affinity).unwrap();
++
++    // And now re-check the affinity which should be only the one we set.
++    let updated_affinity = sched_getaffinity(Pid::from_raw(0)).unwrap();
++    for field in 0..CpuSet::count() {
++        // Should be set only for the CPU we set previously
++        assert_eq!(updated_affinity.is_set(field).unwrap(), field==last_valid_cpu)
++    }
++
++    // Finally, reset the initial CPU set
++    sched_setaffinity(Pid::from_raw(0), &initial_affinity).unwrap();
++}
+diff --git a/third_party/rust/nix/test/test_stat.rs b/third_party/rust/nix/test/test_stat.rs
+index 1173455fae8db..0b9466685607b 100644
+--- a/third_party/rust/nix/test/test_stat.rs
++++ b/third_party/rust/nix/test/test_stat.rs
+@@ -1,15 +1,26 @@
+-use std::fs::{self, File};
++#[cfg(not(target_os = "redox"))]
++use std::fs;
++use std::fs::File;
++#[cfg(not(target_os = "redox"))]
+ use std::os::unix::fs::{symlink, PermissionsExt};
+ use std::os::unix::prelude::AsRawFd;
++#[cfg(not(target_os = "redox"))]
+ use std::time::{Duration, UNIX_EPOCH};
++#[cfg(not(target_os = "redox"))]
+ use std::path::Path;
+ 
+-#[cfg(not(any(target_os = "netbsd")))]
++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
+ use libc::{S_IFMT, S_IFLNK, mode_t};
+ 
++#[cfg(not(target_os = "redox"))]
+ use nix::{fcntl, Error};
+-use nix::errno::{Errno};
+-use nix::sys::stat::{self, fchmod, fchmodat, futimens, stat, utimes, utimensat, mkdirat};
++#[cfg(not(target_os = "redox"))]
++use nix::errno::Errno;
++#[cfg(not(target_os = "redox"))]
++use nix::sys::stat::{self, futimens, utimes};
++use nix::sys::stat::{fchmod, stat};
++#[cfg(not(target_os = "redox"))]
++use nix::sys::stat::{fchmodat, utimensat, mkdirat};
+ #[cfg(any(target_os = "linux",
+           target_os = "haiku",
+           target_os = "ios",
+@@ -17,15 +28,19 @@ use nix::sys::stat::{self, fchmod, fchmodat, futimens, stat, utimes, utimensat,
+           target_os = "freebsd",
+           target_os = "netbsd"))]
+ use nix::sys::stat::lutimes;
+-use nix::sys::stat::{Mode, FchmodatFlags, UtimensatFlags};
++#[cfg(not(target_os = "redox"))]
++use nix::sys::stat::{FchmodatFlags, UtimensatFlags};
++use nix::sys::stat::Mode;
+ 
+-#[cfg(not(any(target_os = "netbsd")))]
++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
+ use nix::sys::stat::FileStat;
+ 
++#[cfg(not(target_os = "redox"))]
+ use nix::sys::time::{TimeSpec, TimeVal, TimeValLike};
++#[cfg(not(target_os = "redox"))]
+ use nix::unistd::chdir;
+ 
+-#[cfg(not(any(target_os = "netbsd")))]
++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
+ use nix::Result;
+ use tempfile;
+ 
+@@ -33,27 +48,27 @@ use tempfile;
+ // uid and gid are signed on Windows, but not on other platforms. This function
+ // allows warning free compiles on all platforms, and can be removed when
+ // expression-level #[allow] is available.
+-#[cfg(not(any(target_os = "netbsd")))]
++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
+ fn valid_uid_gid(stat: FileStat) -> bool {
+     // uid could be 0 for the `root` user. This quite possible when
+     // the tests are being run on a rooted Android device.
+     stat.st_uid >= 0 && stat.st_gid >= 0
+ }
+ 
+-#[cfg(not(any(target_os = "netbsd")))]
++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
+ fn assert_stat_results(stat_result: Result<FileStat>) {
+     let stats = stat_result.expect("stat call failed");
+     assert!(stats.st_dev > 0);      // must be positive integer, exact number machine dependent
+     assert!(stats.st_ino > 0);      // inode is positive integer, exact number machine dependent
+     assert!(stats.st_mode > 0);     // must be positive integer
+-    assert!(stats.st_nlink == 1);   // there links created, must be 1
++    assert_eq!(stats.st_nlink, 1);   // there links created, must be 1
+     assert!(valid_uid_gid(stats));  // must be positive integers
+-    assert!(stats.st_size == 0);    // size is 0 because we did not write anything to the file
++    assert_eq!(stats.st_size, 0);    // size is 0 because we did not write anything to the file
+     assert!(stats.st_blksize > 0);  // must be positive integer, exact number machine dependent
+     assert!(stats.st_blocks <= 16);  // Up to 16 blocks can be allocated for a blank file
+ }
+ 
+-#[cfg(not(any(target_os = "netbsd")))]
++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
+ fn assert_lstat_results(stat_result: Result<FileStat>) {
+     let stats = stat_result.expect("stat call failed");
+     assert!(stats.st_dev > 0);      // must be positive integer, exact number machine dependent
+@@ -63,8 +78,8 @@ fn assert_lstat_results(stat_result: Result<FileStat>) {
+     // st_mode is c_uint (u32 on Android) while S_IFMT is mode_t
+     // (u16 on Android), and that will be a compile error.
+     // On other platforms they are the same (either both are u16 or u32).
+-    assert!((stats.st_mode as usize) & (S_IFMT as usize) == S_IFLNK as usize); // should be a link
+-    assert!(stats.st_nlink == 1);   // there links created, must be 1
++    assert_eq!((stats.st_mode as usize) & (S_IFMT as usize), S_IFLNK as usize); // should be a link
++    assert_eq!(stats.st_nlink, 1);   // there links created, must be 1
+     assert!(valid_uid_gid(stats));  // must be positive integers
+     assert!(stats.st_size > 0);    // size is > 0 because it points to another file
+     assert!(stats.st_blksize > 0);  // must be positive integer, exact number machine dependent
+@@ -76,7 +91,7 @@ fn assert_lstat_results(stat_result: Result<FileStat>) {
+ }
+ 
+ #[test]
+-#[cfg(not(any(target_os = "netbsd")))]
++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
+ fn test_stat_and_fstat() {
+     use nix::sys::stat::fstat;
+ 
+@@ -92,7 +107,7 @@ fn test_stat_and_fstat() {
+ }
+ 
+ #[test]
+-#[cfg(not(any(target_os = "netbsd")))]
++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
+ fn test_fstatat() {
+     let tempdir = tempfile::tempdir().unwrap();
+     let filename = tempdir.path().join("foo.txt");
+@@ -108,7 +123,7 @@ fn test_fstatat() {
+ }
+ 
+ #[test]
+-#[cfg(not(any(target_os = "netbsd")))]
++#[cfg(not(any(target_os = "netbsd", target_os = "redox")))]
+ fn test_stat_fstat_lstat() {
+     use nix::sys::stat::{fstat, lstat};
+ 
+@@ -155,8 +170,9 @@ fn test_fchmod() {
+ }
+ 
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_fchmodat() {
+-    let _dr = ::DirRestore::new();
++    let _dr = crate::DirRestore::new();
+     let tempdir = tempfile::tempdir().unwrap();
+     let filename = "foo.txt";
+     let fullpath = tempdir.path().join(filename);
+@@ -186,6 +202,7 @@ fn test_fchmodat() {
+ ///
+ /// The atime and mtime are expressed with a resolution of seconds because some file systems
+ /// (like macOS's HFS+) do not have higher granularity.
++#[cfg(not(target_os = "redox"))]
+ fn assert_times_eq(exp_atime_sec: u64, exp_mtime_sec: u64, attr: &fs::Metadata) {
+     assert_eq!(
+         Duration::new(exp_atime_sec, 0),
+@@ -196,6 +213,7 @@ fn assert_times_eq(exp_atime_sec: u64, exp_mtime_sec: u64, attr: &fs::Metadata)
+ }
+ 
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_utimes() {
+     let tempdir = tempfile::tempdir().unwrap();
+     let fullpath = tempdir.path().join("file");
+@@ -231,6 +249,7 @@ fn test_lutimes() {
+ }
+ 
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_futimens() {
+     let tempdir = tempfile::tempdir().unwrap();
+     let fullpath = tempdir.path().join("file");
+@@ -243,8 +262,9 @@ fn test_futimens() {
+ }
+ 
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_utimensat() {
+-    let _dr = ::DirRestore::new();
++    let _dr = crate::DirRestore::new();
+     let tempdir = tempfile::tempdir().unwrap();
+     let filename = "foo.txt";
+     let fullpath = tempdir.path().join(filename);
+@@ -264,6 +284,7 @@ fn test_utimensat() {
+ }
+ 
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_mkdirat_success_path() {
+     let tempdir = tempfile::tempdir().unwrap();
+     let filename = "example_subdir";
+@@ -273,6 +294,7 @@ fn test_mkdirat_success_path() {
+ }
+ 
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_mkdirat_success_mode() {
+     let expected_bits = stat::SFlag::S_IFDIR.bits() | stat::Mode::S_IRWXU.bits();
+     let tempdir = tempfile::tempdir().unwrap();
+@@ -285,6 +307,7 @@ fn test_mkdirat_success_mode() {
+ }
+ 
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_mkdirat_fail() {
+     let tempdir = tempfile::tempdir().unwrap();
+     let not_dir_filename= "example_not_dir";
+diff --git a/third_party/rust/nix/test/test_time.rs b/third_party/rust/nix/test/test_time.rs
+new file mode 100644
+index 0000000000000..c321352d79c16
+--- /dev/null
++++ b/third_party/rust/nix/test/test_time.rs
+@@ -0,0 +1,56 @@
++#[cfg(any(
++    target_os = "freebsd",
++    target_os = "dragonfly",
++    target_os = "linux",
++    target_os = "android",
++    target_os = "emscripten",
++))]
++use nix::time::clock_getcpuclockid;
++use nix::time::{clock_getres, clock_gettime, ClockId};
++
++#[test]
++pub fn test_clock_getres() {
++    assert!(clock_getres(ClockId::CLOCK_REALTIME).is_ok());
++}
++
++#[test]
++pub fn test_clock_gettime() {
++    assert!(clock_gettime(ClockId::CLOCK_REALTIME).is_ok());
++}
++
++#[cfg(any(
++    target_os = "freebsd",
++    target_os = "dragonfly",
++    target_os = "linux",
++    target_os = "android",
++    target_os = "emscripten",
++))]
++#[test]
++pub fn test_clock_getcpuclockid() {
++    let clock_id = clock_getcpuclockid(nix::unistd::Pid::this()).unwrap();
++    assert!(clock_gettime(clock_id).is_ok());
++}
++
++#[test]
++pub fn test_clock_id_res() {
++    assert!(ClockId::CLOCK_REALTIME.res().is_ok());
++}
++
++#[test]
++pub fn test_clock_id_now() {
++    assert!(ClockId::CLOCK_REALTIME.now().is_ok());
++}
++
++#[cfg(any(
++    target_os = "freebsd",
++    target_os = "dragonfly",
++    target_os = "linux",
++    target_os = "android",
++    target_os = "emscripten",
++))]
++#[test]
++pub fn test_clock_id_pid_cpu_clock_id() {
++    assert!(ClockId::pid_cpu_clock_id(nix::unistd::Pid::this())
++        .map(ClockId::now)
++        .is_ok());
++}
+diff --git a/third_party/rust/nix/test/test_unistd.rs b/third_party/rust/nix/test/test_unistd.rs
+index 46196dec7ccce..16a8a05dd6d08 100644
+--- a/third_party/rust/nix/test/test_unistd.rs
++++ b/third_party/rust/nix/test/test_unistd.rs
+@@ -1,26 +1,39 @@
+-use nix::fcntl::{self, fcntl, FcntlArg, FdFlag, open, OFlag, readlink};
++#[cfg(not(target_os = "redox"))]
++use nix::fcntl::{self, open, readlink};
++use nix::fcntl::{fcntl, FcntlArg, FdFlag, OFlag};
+ use nix::unistd::*;
+ use nix::unistd::ForkResult::*;
++#[cfg(not(target_os = "redox"))]
+ use nix::sys::signal::{SaFlags, SigAction, SigHandler, SigSet, Signal, sigaction};
+ use nix::sys::wait::*;
+ use nix::sys::stat::{self, Mode, SFlag};
++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
++use nix::pty::{posix_openpt, grantpt, unlockpt, ptsname};
+ use nix::errno::Errno;
++#[cfg(not(target_os = "redox"))]
+ use nix::Error;
+ use std::{env, iter};
++#[cfg(not(target_os = "redox"))]
+ use std::ffi::CString;
+-use std::fs::{self, DirBuilder, File};
++#[cfg(not(target_os = "redox"))]
++use std::fs::DirBuilder;
++use std::fs::{self, File};
+ use std::io::Write;
+ use std::os::unix::prelude::*;
+-use tempfile::{self, tempfile};
+-use libc::{self, _exit, off_t};
++#[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() {
+-    let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+     // Safe: Child only calls `_exit`, which is signal-safe
+-    match fork().expect("Error: Fork Failed") {
++    match unsafe{fork()}.expect("Error: Fork Failed") {
+         Child => unsafe { _exit(0) },
+         Parent { child } => {
+             // assert that child was created and pid > 0
+@@ -29,7 +42,7 @@ fn test_fork_and_waitpid() {
+             let wait_status = waitpid(child, None);
+             match wait_status {
+                 // assert that waitpid returned correct status and the pid is the one of the child
+-                Ok(WaitStatus::Exited(pid_t, _)) =>  assert!(pid_t == child),
++                Ok(WaitStatus::Exited(pid_t, _)) =>  assert_eq!(pid_t, child),
+ 
+                 // panic, must never happen
+                 s @ Ok(_) => panic!("Child exited {:?}, should never happen", s),
+@@ -45,10 +58,10 @@ fn test_fork_and_waitpid() {
+ #[test]
+ fn test_wait() {
+     // Grab FORK_MTX so wait doesn't reap a different test's child process
+-    let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+     // Safe: Child only calls `_exit`, which is signal-safe
+-    match fork().expect("Error: Fork Failed") {
++    match unsafe{fork()}.expect("Error: Fork Failed") {
+         Child => unsafe { _exit(0) },
+         Parent { child } => {
+             let wait_status = wait();
+@@ -81,8 +94,9 @@ fn test_mkstemp_directory() {
+ }
+ 
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_mkfifo() {
+-    let tempdir = tempfile::tempdir().unwrap();
++    let tempdir = tempdir().unwrap();
+     let mkfifo_fifo = tempdir.path().join("mkfifo_fifo");
+ 
+     mkfifo(&mkfifo_fifo, Mode::S_IRUSR).unwrap();
+@@ -93,11 +107,70 @@ fn test_mkfifo() {
+ }
+ 
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_mkfifo_directory() {
+     // mkfifo should fail if a directory is given
+     assert!(mkfifo(&env::temp_dir(), Mode::S_IRUSR).is_err());
+ }
+ 
++#[test]
++#[cfg(not(any(
++    target_os = "macos", target_os = "ios",
++    target_os = "android", target_os = "redox")))]
++fn test_mkfifoat_none() {
++    let _m = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++    let tempdir = tempdir().unwrap();
++    let mkfifoat_fifo = tempdir.path().join("mkfifoat_fifo");
++
++    mkfifoat(None, &mkfifoat_fifo, Mode::S_IRUSR).unwrap();
++
++    let stats = stat::stat(&mkfifoat_fifo).unwrap();
++    let typ = stat::SFlag::from_bits_truncate(stats.st_mode);
++    assert_eq!(typ, SFlag::S_IFIFO);
++}
++
++#[test]
++#[cfg(not(any(
++    target_os = "macos", target_os = "ios",
++    target_os = "android", target_os = "redox")))]
++fn test_mkfifoat() {
++    let tempdir = tempdir().unwrap();
++    let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
++    let mkfifoat_name = "mkfifoat_name";
++
++    mkfifoat(Some(dirfd), mkfifoat_name, Mode::S_IRUSR).unwrap();
++
++    let stats = stat::fstatat(dirfd, mkfifoat_name, fcntl::AtFlags::empty()).unwrap();
++    let typ = stat::SFlag::from_bits_truncate(stats.st_mode);
++    assert_eq!(typ, SFlag::S_IFIFO);
++}
++
++#[test]
++#[cfg(not(any(
++    target_os = "macos", target_os = "ios",
++    target_os = "android", target_os = "redox")))]
++fn test_mkfifoat_directory_none() {
++    let _m = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++    // mkfifoat should fail if a directory is given
++    assert!(!mkfifoat(None, &env::temp_dir(), Mode::S_IRUSR).is_ok());
++}
++
++#[test]
++#[cfg(not(any(
++    target_os = "macos", target_os = "ios",
++    target_os = "android", target_os = "redox")))]
++fn test_mkfifoat_directory() {
++    // mkfifoat should fail if a directory is given
++    let tempdir = tempdir().unwrap();
++    let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
++    let mkfifoat_dir = "mkfifoat_dir";
++    stat::mkdirat(dirfd, mkfifoat_dir, Mode::S_IRUSR).unwrap();
++
++    assert!(!mkfifoat(Some(dirfd), mkfifoat_dir, Mode::S_IRUSR).is_ok());
++}
++
+ #[test]
+ fn test_getpid() {
+     let pid: ::libc::pid_t = getpid().into();
+@@ -107,11 +180,12 @@ fn test_getpid() {
+ }
+ 
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_getsid() {
+     let none_sid: ::libc::pid_t = getsid(None).unwrap().into();
+     let pid_sid: ::libc::pid_t = getsid(Some(getpid())).unwrap().into();
+     assert!(none_sid > 0);
+-    assert!(none_sid == pid_sid);
++    assert_eq!(none_sid, pid_sid);
+ }
+ 
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+@@ -127,12 +201,12 @@ mod linux_android {
+ 
+ #[test]
+ // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms
+-#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++#[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");
+ 
+-    let _m = ::GROUPS_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m = crate::GROUPS_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+     // Save the existing groups
+     let old_groups = getgroups().unwrap();
+@@ -150,13 +224,13 @@ fn test_setgroups() {
+ 
+ #[test]
+ // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms
+-#[cfg(not(any(target_os = "ios", target_os = "macos")))]
++#[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.
+     skip_if_not_root!("test_initgroups");
+ 
+-    let _m = ::GROUPS_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m = crate::GROUPS_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+     // Save the existing groups
+     let old_groups = getgroups().unwrap();
+@@ -180,11 +254,53 @@ fn test_initgroups() {
+     setgroups(&old_groups).unwrap();
+ }
+ 
++#[cfg(not(target_os = "redox"))]
+ macro_rules! execve_test_factory(
+     ($test_name:ident, $syscall:ident, $exe: expr $(, $pathname:expr, $flags:expr)*) => (
+-    #[test]
+-    fn $test_name() {
+-        let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++
++    #[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(), )*
++            &[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)*)
++    }
++
++    fn syscall_cstring() -> Result<std::convert::Infallible, nix::Error> {
++        $syscall(
++            $exe,
++            $(CString::new($pathname).unwrap().as_c_str(), )*
++            &[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)*)
++    }
++
++    fn common_test(syscall: fn() -> Result<std::convert::Infallible, nix::Error>) {
++        if "execveat" == stringify!($syscall) {
++            // Though undocumented, Docker's default seccomp profile seems to
++            // block this syscall.  https://github.com/nix-rust/nix/issues/1122
++            skip_if_seccomp!($test_name);
++        }
++
++        let m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+         // The `exec`d process will write to `writer`, and we'll read that
+         // data from `reader`.
+         let (reader, writer) = pipe().unwrap();
+@@ -192,27 +308,21 @@ macro_rules! execve_test_factory(
+         // Safe: Child calls `exit`, `dup`, `close` and the provided `exec*` family function.
+         // NOTE: Technically, this makes the macro unsafe to use because you could pass anything.
+         //       The tests make sure not to do that, though.
+-        match fork().unwrap() {
++        match unsafe{fork()}.unwrap() {
+             Child => {
+-                // Close stdout.
+-                close(1).unwrap();
+                 // Make `writer` be the stdout of the new process.
+-                dup(writer).unwrap();
+-                // exec!
+-                $syscall(
+-                    $exe,
+-                    $(&CString::new($pathname).unwrap(), )*
+-                    &[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()]
+-                    $(, $flags)*).unwrap();
++                dup2(writer, 1).unwrap();
++                let r = syscall();
++                let _ = std::io::stderr()
++                    .write_all(format!("{:?}", r).as_bytes());
++                // Should only get here in event of error
++                unsafe{ _exit(1) };
+             },
+             Parent { child } => {
+                 // Wait for the child to exit.
+-                waitpid(child, None).unwrap();
++                let ws = waitpid(child, None);
++                drop(m);
++                assert_eq!(ws, Ok(WaitStatus::Exited(child, 0)));
+                 // Read 1024 bytes.
+                 let mut buf = [0u8; 1024];
+                 read(reader, &mut buf).unwrap();
+@@ -224,23 +334,43 @@ macro_rules! execve_test_factory(
+             }
+         }
+     }
++
++    // 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);
++    }
++    }
++
+     )
+ );
+ 
+ cfg_if!{
+     if #[cfg(target_os = "android")] {
+-        execve_test_factory!(test_execve, execve, &CString::new("/system/bin/sh").unwrap());
++        execve_test_factory!(test_execve, execve, CString::new("/system/bin/sh").unwrap().as_c_str());
+         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"))] {
+-        execve_test_factory!(test_execve, execve, &CString::new("/bin/sh").unwrap());
++        // 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",
+                         target_os = "ios",
+                         target_os = "macos",
+                         target_os = "netbsd",
+                         target_os = "openbsd"))] {
+-        execve_test_factory!(test_execve, execve, &CString::new("/bin/sh").unwrap());
++        execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap().as_c_str());
+         // No fexecve() on DragonFly, ios, macos, NetBSD, OpenBSD.
+         //
+         // Note for NetBSD and OpenBSD: although rust-lang/libc includes it
+@@ -255,13 +385,16 @@ execve_test_factory!(test_execvpe, execvpe, &CString::new("sh").unwrap());
+ 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);
+@@ -273,11 +406,12 @@ cfg_if!{
+ }
+ 
+ #[test]
++#[cfg(not(target_os = "fuchsia"))]
+ fn test_fchdir() {
+     // fchdir changes the process's cwd
+-    let _dr = ::DirRestore::new();
++    let _dr = crate::DirRestore::new();
+ 
+-    let tmpdir = tempfile::tempdir().unwrap();
++    let tmpdir = tempdir().unwrap();
+     let tmpdir_path = tmpdir.path().canonicalize().unwrap();
+     let tmpdir_fd = File::open(&tmpdir_path).unwrap().into_raw_fd();
+ 
+@@ -290,9 +424,9 @@ fn test_fchdir() {
+ #[test]
+ fn test_getcwd() {
+     // chdir changes the process's cwd
+-    let _dr = ::DirRestore::new();
++    let _dr = crate::DirRestore::new();
+ 
+-    let tmpdir = tempfile::tempdir().unwrap();
++    let tmpdir = tempdir().unwrap();
+     let tmpdir_path = tmpdir.path().canonicalize().unwrap();
+     assert!(chdir(&tmpdir_path).is_ok());
+     assert_eq!(getcwd().unwrap(), tmpdir_path);
+@@ -317,7 +451,7 @@ fn test_chown() {
+     let uid = Some(getuid());
+     let gid = Some(getgid());
+ 
+-    let tempdir = tempfile::tempdir().unwrap();
++    let tempdir = tempdir().unwrap();
+     let path = tempdir.path().join("file");
+     {
+         File::create(&path).unwrap();
+@@ -332,13 +466,29 @@ fn test_chown() {
+ }
+ 
+ #[test]
++fn test_fchown() {
++    // Testing for anything other than our own UID/GID is hard.
++    let uid = Some(getuid());
++    let gid = Some(getgid());
++
++    let path = tempfile().unwrap();
++    let fd = path.as_raw_fd();
++
++    fchown(fd, uid, gid).unwrap();
++    fchown(fd, uid, None).unwrap();
++    fchown(fd, None, gid).unwrap();
++    fchown(999999999, uid, gid).unwrap_err();
++}
++
++#[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_fchownat() {
+-    let _dr = ::DirRestore::new();
++    let _dr = crate::DirRestore::new();
+     // Testing for anything other than our own UID/GID is hard.
+     let uid = Some(getuid());
+     let gid = Some(getgid());
+ 
+-    let tempdir = tempfile::tempdir().unwrap();
++    let tempdir = tempdir().unwrap();
+     let path = tempdir.path().join("file");
+     {
+         File::create(&path).unwrap();
+@@ -366,7 +516,7 @@ fn test_lseek() {
+     lseek(tmpfd, offset, Whence::SeekSet).unwrap();
+ 
+     let mut buf = [0u8; 7];
+-    ::read_exact(tmpfd, &mut buf);
++    crate::read_exact(tmpfd, &mut buf);
+     assert_eq!(b"f123456", &buf);
+ 
+     close(tmpfd).unwrap();
+@@ -383,7 +533,7 @@ fn test_lseek64() {
+     lseek64(tmpfd, 5, Whence::SeekSet).unwrap();
+ 
+     let mut buf = [0u8; 7];
+-    ::read_exact(tmpfd, &mut buf);
++    crate::read_exact(tmpfd, &mut buf);
+     assert_eq!(b"f123456", &buf);
+ 
+     close(tmpfd).unwrap();
+@@ -403,7 +553,7 @@ cfg_if!{
+                 skip_if_jailed!("test_acct");
+             }
+         }
+-    } else {
++    } else if #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))] {
+         macro_rules! require_acct{
+             () => {
+                 skip_if_not_root!("test_acct");
+@@ -413,12 +563,13 @@ cfg_if!{
+ }
+ 
+ #[test]
++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
+ fn test_acct() {
+     use tempfile::NamedTempFile;
+     use std::process::Command;
+     use std::{thread, time};
+ 
+-    let _m = ::FORK_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m = crate::FORK_MTX.lock().expect("Mutex got poisoned by another test");
+     require_acct!();
+ 
+     let file = NamedTempFile::new().unwrap();
+@@ -481,6 +632,14 @@ fn test_pipe() {
+ 
+ // pipe2(2) is the same as pipe(2), except it allows setting some flags.  Check
+ // that we can set a flag.
++#[cfg(any(target_os = "android",
++          target_os = "dragonfly",
++          target_os = "emscripten",
++          target_os = "freebsd",
++          target_os = "linux",
++          target_os = "netbsd",
++          target_os = "openbsd",
++          target_os = "redox"))]
+ #[test]
+ fn test_pipe2() {
+     let (fd0, fd1) = pipe2(OFlag::O_CLOEXEC).unwrap();
+@@ -491,8 +650,9 @@ fn test_pipe2() {
+ }
+ 
+ #[test]
++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
+ fn test_truncate() {
+-    let tempdir = tempfile::tempdir().unwrap();
++    let tempdir = tempdir().unwrap();
+     let path = tempdir.path().join("file");
+ 
+     {
+@@ -509,7 +669,7 @@ fn test_truncate() {
+ 
+ #[test]
+ fn test_ftruncate() {
+-    let tempdir = tempfile::tempdir().unwrap();
++    let tempdir = tempdir().unwrap();
+     let path = tempdir.path().join("file");
+ 
+     let tmpfd = {
+@@ -527,17 +687,26 @@ fn test_ftruncate() {
+ }
+ 
+ // Used in `test_alarm`.
++#[cfg(not(target_os = "redox"))]
+ static mut ALARM_CALLED: bool = false;
+ 
+ // Used in `test_alarm`.
++#[cfg(not(target_os = "redox"))]
+ pub extern fn alarm_signal_handler(raw_signal: libc::c_int) {
+     assert_eq!(raw_signal, libc::SIGALRM, "unexpected signal: {}", raw_signal);
+     unsafe { ALARM_CALLED = true };
+ }
+ 
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_alarm() {
+-    let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++    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);
+     let signal_action = SigAction::new(handler, SaFlags::SA_RESTART, SigSet::empty());
+@@ -554,8 +723,16 @@ fn test_alarm() {
+ 
+     // 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 {
+@@ -565,8 +742,9 @@ fn test_alarm() {
+ }
+ 
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_canceling_alarm() {
+-    let _m = ::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
++    let _m = crate::SIGNAL_MTX.lock().expect("Mutex got poisoned by another test");
+ 
+     assert_eq!(alarm::cancel(), None);
+ 
+@@ -575,15 +753,17 @@ fn test_canceling_alarm() {
+ }
+ 
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_symlinkat() {
+-    let mut buf = [0; 1024];
+-    let tempdir = tempfile::tempdir().unwrap();
++    let _m = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++    let tempdir = tempdir().unwrap();
+ 
+     let target = tempdir.path().join("a");
+     let linkpath = tempdir.path().join("b");
+     symlinkat(&target, None, &linkpath).unwrap();
+     assert_eq!(
+-        readlink(&linkpath, &mut buf).unwrap().to_str().unwrap(),
++        readlink(&linkpath).unwrap().to_str().unwrap(),
+         target.to_str().unwrap()
+     );
+ 
+@@ -592,7 +772,7 @@ fn test_symlinkat() {
+     let linkpath = "d";
+     symlinkat(target, Some(dirfd), linkpath).unwrap();
+     assert_eq!(
+-        readlink(&tempdir.path().join(linkpath), &mut buf)
++        readlink(&tempdir.path().join(linkpath))
+             .unwrap()
+             .to_str()
+             .unwrap(),
+@@ -600,10 +780,154 @@ fn test_symlinkat() {
+     );
+ }
+ 
++#[test]
++#[cfg(not(target_os = "redox"))]
++fn test_linkat_file() {
++    let tempdir = tempdir().unwrap();
++    let oldfilename = "foo.txt";
++    let oldfilepath = tempdir.path().join(oldfilename);
++
++    let newfilename = "bar.txt";
++    let newfilepath = tempdir.path().join(newfilename);
++
++    // Create file
++    File::create(&oldfilepath).unwrap();
++
++    // Get file descriptor for base directory
++    let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++
++    // Attempt hard link file at relative path
++    linkat(Some(dirfd), oldfilename, Some(dirfd), newfilename, LinkatFlags::SymlinkFollow).unwrap();
++    assert!(newfilepath.exists());
++}
++
++#[test]
++#[cfg(not(target_os = "redox"))]
++fn test_linkat_olddirfd_none() {
++    let _dr = crate::DirRestore::new();
++
++    let tempdir_oldfile = tempdir().unwrap();
++    let oldfilename = "foo.txt";
++    let oldfilepath = tempdir_oldfile.path().join(oldfilename);
++
++    let tempdir_newfile = tempdir().unwrap();
++    let newfilename = "bar.txt";
++    let newfilepath = tempdir_newfile.path().join(newfilename);
++
++    // Create file
++    File::create(&oldfilepath).unwrap();
++
++    // Get file descriptor for base directory of new file
++    let dirfd = fcntl::open(tempdir_newfile.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++
++    // Attempt hard link file using curent working directory as relative path for old file path
++    chdir(tempdir_oldfile.path()).unwrap();
++    linkat(None, oldfilename, Some(dirfd), newfilename, LinkatFlags::SymlinkFollow).unwrap();
++    assert!(newfilepath.exists());
++}
++
++#[test]
++#[cfg(not(target_os = "redox"))]
++fn test_linkat_newdirfd_none() {
++    let _dr = crate::DirRestore::new();
++
++    let tempdir_oldfile = tempdir().unwrap();
++    let oldfilename = "foo.txt";
++    let oldfilepath = tempdir_oldfile.path().join(oldfilename);
++
++    let tempdir_newfile = tempdir().unwrap();
++    let newfilename = "bar.txt";
++    let newfilepath = tempdir_newfile.path().join(newfilename);
++
++    // Create file
++    File::create(&oldfilepath).unwrap();
++
++    // Get file descriptor for base directory of old file
++    let dirfd = fcntl::open(tempdir_oldfile.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++
++    // Attempt hard link file using current working directory as relative path for new file path
++    chdir(tempdir_newfile.path()).unwrap();
++    linkat(Some(dirfd), oldfilename, None, newfilename, LinkatFlags::SymlinkFollow).unwrap();
++    assert!(newfilepath.exists());
++}
++
++#[test]
++#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))]
++fn test_linkat_no_follow_symlink() {
++    let _m = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++    let tempdir = tempdir().unwrap();
++    let oldfilename = "foo.txt";
++    let oldfilepath = tempdir.path().join(oldfilename);
++
++    let symoldfilename = "symfoo.txt";
++    let symoldfilepath = tempdir.path().join(symoldfilename);
++
++    let newfilename = "nofollowsymbar.txt";
++    let newfilepath = tempdir.path().join(newfilename);
++
++    // Create file
++    File::create(&oldfilepath).unwrap();
++
++    // Create symlink to file
++    symlinkat(&oldfilepath, None, &symoldfilepath).unwrap();
++
++    // Get file descriptor for base directory
++    let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++
++    // Attempt link symlink of file at relative path
++    linkat(Some(dirfd), symoldfilename, Some(dirfd), newfilename, LinkatFlags::NoSymlinkFollow).unwrap();
++
++    // Assert newfile is actually a symlink to oldfile.
++    assert_eq!(
++        readlink(&newfilepath)
++            .unwrap()
++            .to_str()
++            .unwrap(),
++        oldfilepath.to_str().unwrap()
++    );
++}
++
++#[test]
++#[cfg(not(target_os = "redox"))]
++fn test_linkat_follow_symlink() {
++    let _m = crate::CWD_LOCK.read().expect("Mutex got poisoned by another test");
++
++    let tempdir = tempdir().unwrap();
++    let oldfilename = "foo.txt";
++    let oldfilepath = tempdir.path().join(oldfilename);
++
++    let symoldfilename = "symfoo.txt";
++    let symoldfilepath = tempdir.path().join(symoldfilename);
++
++    let newfilename = "nofollowsymbar.txt";
++    let newfilepath = tempdir.path().join(newfilename);
++
++    // Create file
++    File::create(&oldfilepath).unwrap();
++
++    // Create symlink to file
++    symlinkat(&oldfilepath, None, &symoldfilepath).unwrap();
++
++    // Get file descriptor for base directory
++    let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
++
++    // Attempt link target of symlink of file at relative path
++    linkat(Some(dirfd), symoldfilename, Some(dirfd), newfilename, LinkatFlags::SymlinkFollow).unwrap();
++
++    let newfilestat = stat::stat(&newfilepath).unwrap();
++
++    // Check the file type of the new link
++    assert!((stat::SFlag::from_bits_truncate(newfilestat.st_mode) & SFlag::S_IFMT) ==  SFlag::S_IFREG);
++
++    // Check the number of hard links to the original file
++    assert_eq!(newfilestat.st_nlink, 2);
++}
+ 
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_unlinkat_dir_noremovedir() {
+-    let tempdir = tempfile::tempdir().unwrap();
++    let tempdir = tempdir().unwrap();
+     let dirname = "foo_dir";
+     let dirpath = tempdir.path().join(dirname);
+ 
+@@ -619,8 +943,9 @@ fn test_unlinkat_dir_noremovedir() {
+  }
+ 
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_unlinkat_dir_removedir() {
+-    let tempdir = tempfile::tempdir().unwrap();
++    let tempdir = tempdir().unwrap();
+     let dirname = "foo_dir";
+     let dirpath = tempdir.path().join(dirname);
+ 
+@@ -636,8 +961,9 @@ fn test_unlinkat_dir_removedir() {
+  }
+ 
+ #[test]
++#[cfg(not(target_os = "redox"))]
+ fn test_unlinkat_file() {
+-    let tempdir = tempfile::tempdir().unwrap();
++    let tempdir = tempdir().unwrap();
+     let filename = "foo.txt";
+     let filepath = tempdir.path().join(filename);
+ 
+@@ -654,7 +980,7 @@ fn test_unlinkat_file() {
+ 
+ #[test]
+ fn test_access_not_existing() {
+-    let tempdir = tempfile::tempdir().unwrap();
++    let tempdir = tempdir().unwrap();
+     let dir = tempdir.path().join("does_not_exist.txt");
+     assert_eq!(access(&dir, AccessFlags::F_OK).err().unwrap().as_errno().unwrap(),
+                Errno::ENOENT);
+@@ -662,8 +988,123 @@ fn test_access_not_existing() {
+ 
+ #[test]
+ fn test_access_file_exists() {
+-    let tempdir = tempfile::tempdir().unwrap();
++    let tempdir = tempdir().unwrap();
+     let path  = tempdir.path().join("does_exist.txt");
+     let _file = File::create(path.clone()).unwrap();
+     assert!(access(&path, AccessFlags::R_OK | AccessFlags::W_OK).is_ok());
+ }
++
++/// Tests setting the filesystem UID with `setfsuid`.
++#[cfg(any(target_os = "linux", target_os = "android"))]
++#[test]
++fn test_setfsuid() {
++    use std::os::unix::fs::PermissionsExt;
++    use std::{fs, io, thread};
++    require_capability!(CAP_SETUID);
++
++    // get the UID of the "nobody" user
++    let nobody = User::from_name("nobody").unwrap().unwrap();
++
++    // create a temporary file with permissions '-rw-r-----'
++    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);
++
++    // spawn a new thread where to test setfsuid
++    thread::spawn(move || {
++        // set filesystem UID
++        let fuid = setfsuid(nobody.uid);
++        // trying to open the temporary file should fail with EACCES
++        let res = fs::File::open(&temp_path);
++        assert!(res.is_err());
++        assert_eq!(res.err().unwrap().kind(), io::ErrorKind::PermissionDenied);
++
++        // assert fuid actually changes
++        let prev_fuid = setfsuid(Uid::from_raw(-1i32 as u32));
++        assert_ne!(prev_fuid, fuid);
++    })
++    .join()
++    .unwrap();
++
++    // open the temporary file with the current thread filesystem UID
++    fs::File::open(temp_path_2).unwrap();
++}
++
++#[test]
++#[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);
++
++    // on linux, we can just call ttyname on the pty master directly, but
++    // apparently osx requires that ttyname is called on a slave pty (can't
++    // find this documented anywhere, but it seems to empirically be the case)
++    grantpt(&fd).expect("grantpt failed");
++    unlockpt(&fd).expect("unlockpt failed");
++    let sname = unsafe { ptsname(&fd) }.expect("ptsname failed");
++    let fds = open(
++        Path::new(&sname),
++        OFlag::O_RDWR,
++        stat::Mode::empty(),
++    ).expect("open failed");
++    assert!(fds > 0);
++
++    let name = ttyname(fds).expect("ttyname failed");
++    assert!(name.starts_with("/dev"));
++}
++
++#[test]
++#[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);
++    assert_eq!(ttyname(fd.as_raw_fd()), Err(Error::Sys(Errno::ENOTTY)));
++}
++
++#[test]
++#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
++fn test_ttyname_invalid_fd() {
++    assert_eq!(ttyname(-1), Err(Error::Sys(Errno::EBADF)));
++}
++
++#[test]
++#[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());
++}

diff --git a/www-client/firefox/firefox-98.0.2.ebuild b/www-client/firefox/firefox-98.0.2.ebuild
index 4b45248..7eee8fb 100644
--- a/www-client/firefox/firefox-98.0.2.ebuild
+++ b/www-client/firefox/firefox-98.0.2.ebuild
@@ -51,6 +51,8 @@ PATCH_URIS=(
 	https://dev.gentoo.org/~{juippis,polynomial-c,whissi,slashbeast}/mozilla/patchsets/${FIREFOX_PATCHSET}
 )
 
+PATCHES=${FILESDIR}/makotokato-riscv64-support-and-zenithal-backported.patch
+
 SRC_URI="${MOZ_SRC_BASE_URI}/source/${MOZ_P}.source.tar.xz -> ${MOZ_P_DISTFILES}.source.tar.xz
 	${PATCH_URIS[@]}"
 
@@ -725,7 +727,7 @@ src_configure() {
 	# For future keywording: This is currently (97.0) only supported on:
 	# amd64, arm, arm64 & x86.
 	# Might want to flip the logic around if Firefox is to support more arches.
-	if use ppc64; then
+	if use ppc64 || use riscv; then
 		mozconfig_add_options_ac '' --disable-sandbox
 	else
 		mozconfig_add_options_ac '' --enable-sandbox


             reply	other threads:[~2022-04-20 13:23 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-04-20 13:23 Yixun Lan [this message]
  -- strict thread matches above, loose matches on Subject: below --
2022-08-31  2:30 [gentoo-commits] proj/riscv:master commit in: www-client/firefox/files/, www-client/firefox/ Yixun Lan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1650460949.07c4b52e96d933d680ba43f71849bae09abd41f2.dlan@gentoo \
    --to=dlan@gentoo.org \
    --cc=gentoo-commits@lists.gentoo.org \
    --cc=gentoo-dev@lists.gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox