* [gentoo-commits] proj/riscv:master commit in: www-client/firefox/files/, www-client/firefox/
@ 2022-04-20 13:23 Yixun Lan
0 siblings, 0 replies; 2+ messages in thread
From: Yixun Lan @ 2022-04-20 13:23 UTC (permalink / raw
To: gentoo-commits
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>(),
++ ®s 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(), ×[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(), ×[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, ×[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(),
++ ×[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) -> ×pec {
++ &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) -> ×pec {
+@@ -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
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [gentoo-commits] proj/riscv:master commit in: www-client/firefox/files/, www-client/firefox/
@ 2022-08-31 2:30 Yixun Lan
0 siblings, 0 replies; 2+ messages in thread
From: Yixun Lan @ 2022-08-31 2:30 UTC (permalink / raw
To: gentoo-commits
commit: 5183cfd4ccbd66fcf23f62c94dd359832eaa7006
Author: Alex Fan <alex.fan.q <AT> gmail <DOT> com>
AuthorDate: Sun Aug 28 05:34:55 2022 +0000
Commit: Yixun Lan <dlan <AT> gentoo <DOT> org>
CommitDate: Wed Aug 31 02:27:40 2022 +0000
URL: https://gitweb.gentoo.org/proj/riscv.git/commit/?id=5183cfd4
www-client/firefox: bump to 103.0.1
update riscv support patch. To avoid huge patches of rust third party
libs, we have to download it on the fly. To do this, network-sandbox
is restricted and ./mach vendor rust is run before ./mach configure.
cargo-vet is disabled as mozbuild cannot pass correct PATH to it with
non-git firefox src and we don't audit libs anyway.
Signed-off-by: Alex Fan <alex.fan.q <AT> gmail.com>
Signed-off-by: Yixun Lan <dlan <AT> gentoo.org>
.../firefox/files/firefox-riscv64-hack.patch | 102 +
.../firefox/files/firefox-riscv64-support.patch | 3283 ++
www-client/firefox/files/firefox-wayland.sh | 7 -
www-client/firefox/files/firefox-x11.sh | 7 -
www-client/firefox/files/firefox.sh | 128 -
.../firefox/files/gentoo-hwaccel-prefs.js-r2 | 5 +
...o-riscv64-support-and-zenithal-backported.patch | 47126 -------------------
www-client/firefox/firefox-103.0.1.ebuild | 1301 +
8 files changed, 4691 insertions(+), 47268 deletions(-)
diff --git a/www-client/firefox/files/firefox-riscv64-hack.patch b/www-client/firefox/files/firefox-riscv64-hack.patch
new file mode 100644
index 0000000..b4fca4d
--- /dev/null
+++ b/www-client/firefox/files/firefox-riscv64-hack.patch
@@ -0,0 +1,102 @@
+Temporary hack to allow us to directly apply diff of matoko's branch. Disable
+rust-vet to skip auditing third party libs in order to download/vendor rust
+deps on non-git firefox src. Skip some style checks, as
+macroassembler support in js/src/jit/ is not complete yet
+
+diff --git a/python/mozbuild/mozbuild/vendor/vendor_rust.py b/python/mozbuild/mozbuild/vendor/vendor_rust.py
+index 7394ccaf40..491bd7fbdb 100644
+--- a/python/mozbuild/mozbuild/vendor/vendor_rust.py
++++ b/python/mozbuild/mozbuild/vendor/vendor_rust.py
+@@ -740,38 +740,40 @@ license file's hash.
+ failed = True
+
+ # Only emit warnings for cargo-vet for now.
+- env = os.environ.copy()
+- env["PATH"] = os.pathsep.join(
+- (
+- str(Path(cargo).parent),
+- os.environ["PATH"],
+- )
+- )
+- flags = ["--output-format=json"]
+- if "MOZ_AUTOMATION" in os.environ:
+- flags.append("--locked")
+- flags.append("--frozen")
+- res = cargo_vet(
+- self,
+- flags,
+- stdout=subprocess.PIPE,
+- env=env,
+- )
+- if res.returncode:
+- vet = json.loads(res.stdout)
+- for failure in vet.get("failures", []):
+- failure["crate"] = failure.pop("name")
+- self.log(
+- logging.ERROR,
+- "cargo_vet_failed",
+- failure,
+- "Missing audit for {crate}:{version} (requires {missing_criteria})."
+- " Run `./mach cargo vet` for more information.",
+- )
+- failed = True
+-
+- if failed:
+- return False
++ #env = os.environ.copy()
++ #env["PATH"] = os.pathsep.join(
++ # (
++ # str(Path(cargo).parent),
++ # os.environ["PATH"],
++ # )
++ #)
++ #print(env["PATH"])
++ #print(self.topsrcdir)
++ #flags = ["--output-format=json"]
++ #if "MOZ_AUTOMATION" in os.environ:
++ # flags.append("--locked")
++ # flags.append("--frozen")
++ #res = cargo_vet(
++ # self,
++ # flags,
++ # stdout=subprocess.PIPE,
++ # env=env,
++ #)
++ #if res.returncode:
++ # vet = json.loads(res.stdout)
++ # for failure in vet.get("failures", []):
++ # failure["crate"] = failure.pop("name")
++ # self.log(
++ # logging.ERROR,
++ # "cargo_vet_failed",
++ # failure,
++ # "Missing audit for {crate}:{version} (requires {missing_criteria})."
++ # " Run `./mach cargo vet` for more information.",
++ # )
++ # failed = True
++
++ #if failed:
++ # return False
+
+ res = subprocess.run(
+ [cargo, "vendor", vendor_dir], cwd=self.topsrcdir, stdout=subprocess.PIPE
+@@ -848,6 +848,7 @@ license file's hash.
+ directory=replace["directory"],
+ )
+ )
++ return True
+
+ if not self._check_licenses(vendor_dir):
+ self.log(
+diff --git a/js/src/build/moz.build b/js/src/build/moz.build
+index 4c48a5c4ff..e68d79447e 100644
+--- a/js/src/build/moz.build
++++ b/js/src/build/moz.build
+@@ -101,7 +101,5 @@ GeneratedFile(
+ inputs=[
+ "!%sjs_static.%s" % (CONFIG["LIB_PREFIX"], CONFIG["LIB_SUFFIX"]),
+- "/config/check_spidermonkey_style.py",
+- "/config/check_macroassembler_style.py",
+ "/config/check_js_opcode.py",
+ ],
+ )
diff --git a/www-client/firefox/files/firefox-riscv64-support.patch b/www-client/firefox/files/firefox-riscv64-support.patch
new file mode 100644
index 0000000..7e9abfc
--- /dev/null
+++ b/www-client/firefox/files/firefox-riscv64-support.patch
@@ -0,0 +1,3283 @@
+patch generated directly from https://github.com/makotokato/gecko-dev by
+
+ git diff master..riscv64 -- . :^third_party
+
+:^third_party is a git feature to exclude third_party/ from diff
+
+diff --git a/.cargo/config.in b/.cargo/config.in
+index 20b8c3fad8..34c5f9a1f4 100644
+--- a/.cargo/config.in
++++ b/.cargo/config.in
+@@ -22,11 +22,6 @@ git = "https://github.com/mozilla/mp4parse-rust"
+ 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/cubeb-pulse-rs"]
+ git = "https://github.com/mozilla/cubeb-pulse-rs"
+ replace-with = "vendored-sources"
+@@ -37,6 +32,11 @@ git = "https://github.com/mozilla/cubeb-coreaudio-rs"
+ replace-with = "vendored-sources"
+ rev = "44eca95823bb57e964cf7b6d9791ed2ccb4b2108"
+
++[source."https://github.com/mozilla/authenticator-rs"]
++git = "https://github.com/mozilla/authenticator-rs"
++replace-with = "vendored-sources"
++rev = "b85bccf0527e42c877573029e8d35ff13ef06f9d"
++
+ [source."https://github.com/mozilla/audioipc"]
+ git = "https://github.com/mozilla/audioipc"
+ replace-with = "vendored-sources"
+diff --git a/Cargo.lock b/Cargo.lock
+index 85a143565c..b4924869cb 100644
+--- a/Cargo.lock
++++ b/Cargo.lock
+@@ -30,14 +30,14 @@ dependencies = [
+
+ [[package]]
+ name = "alsa"
+-version = "0.4.3"
++version = "0.6.0"
+ source = "registry+https://github.com/rust-lang/crates.io-index"
+-checksum = "eb213f6b3e4b1480a60931ca2035794aa67b73103d254715b1db7b70dcb3c934"
++checksum = "5915f52fe2cf65e83924d037b6c5290b7cee097c6b5c8700746e6168a343fd6b"
+ dependencies = [
+ "alsa-sys",
+ "bitflags",
+ "libc",
+- "nix",
++ "nix 0.23.1",
+ ]
+
+ [[package]]
+@@ -359,9 +359,8 @@ dependencies = [
+
+ [[package]]
+ name = "authenticator"
+-version = "0.3.1"
+-source = "registry+https://github.com/rust-lang/crates.io-index"
+-checksum = "08cee7a0952628fde958e149507c2bb321ab4fccfafd225da0b20adc956ef88a"
++version = "0.3.2"
++source = "git+https://github.com/mozilla/authenticator-rs?rev=b85bccf0527e42c877573029e8d35ff13ef06f9d#b85bccf0527e42c877573029e8d35ff13ef06f9d"
+ dependencies = [
+ "bitflags",
+ "core-foundation",
+@@ -369,7 +368,7 @@ dependencies = [
+ "libc",
+ "libudev",
+ "log",
+- "rand 0.7.999",
++ "rand 0.8.5",
+ "runloop",
+ "winapi",
+ ]
+@@ -2204,6 +2203,7 @@ dependencies = [
+ "log",
+ "mapped_hyph",
+ "mdns_service",
++ "midir",
+ "midir_impl",
+ "mio 0.8.0",
+ "moz_asserts",
+@@ -3274,8 +3274,9 @@ dependencies = [
+
+ [[package]]
+ name = "midir"
+-version = "0.7.0"
+-source = "git+https://github.com/mozilla/midir.git?rev=4c11f0ffb5d6a10de4aff40a7b81218b33b94e6f#4c11f0ffb5d6a10de4aff40a7b81218b33b94e6f"
++version = "0.8.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "2c1c68e2b589cce71b14a10d7d1599a845673f9decde80fa9e8500fdccd50dca"
+ dependencies = [
+ "alsa",
+ "bitflags",
+@@ -3283,10 +3284,9 @@ dependencies = [
+ "js-sys",
+ "libc",
+ "memalloc",
+- "nix",
+ "wasm-bindgen",
+ "web-sys",
+- "winapi",
++ "windows",
+ ]
+
+ [[package]]
+@@ -3325,7 +3325,7 @@ dependencies = [
+ "libc",
+ "memmap2 0.2.999",
+ "memoffset 0.5.6",
+- "nix",
++ "nix 0.15.0",
+ "tempfile",
+ "thiserror",
+ ]
+@@ -3735,6 +3735,19 @@ dependencies = [
+ "void",
+ ]
+
++[[package]]
++name = "nix"
++version = "0.23.1"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6"
++dependencies = [
++ "bitflags",
++ "cc",
++ "cfg-if 1.0.0",
++ "libc",
++ "memoffset 0.6.5",
++]
++
+ [[package]]
+ name = "nom"
+ version = "5.999.999"
+@@ -6218,6 +6231,49 @@ version = "0.4.0"
+ source = "registry+https://github.com/rust-lang/crates.io-index"
+ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
++[[package]]
++name = "windows"
++version = "0.32.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "fbedf6db9096bc2364adce0ae0aa636dcd89f3c3f2cd67947062aaf0ca2a10ec"
++dependencies = [
++ "windows_aarch64_msvc",
++ "windows_i686_gnu",
++ "windows_i686_msvc",
++ "windows_x86_64_gnu",
++ "windows_x86_64_msvc",
++]
++
++[[package]]
++name = "windows_aarch64_msvc"
++version = "0.32.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5"
++
++[[package]]
++name = "windows_i686_gnu"
++version = "0.32.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615"
++
++[[package]]
++name = "windows_i686_msvc"
++version = "0.32.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172"
++
++[[package]]
++name = "windows_x86_64_gnu"
++version = "0.32.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc"
++
++[[package]]
++name = "windows_x86_64_msvc"
++version = "0.32.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316"
++
+ [[package]]
+ name = "wineventlog"
+ version = "0.1.0"
+diff --git a/Cargo.toml b/Cargo.toml
+index 2b499a0841..dcf1e401d7 100644
+--- a/Cargo.toml
++++ b/Cargo.toml
+@@ -153,7 +153,6 @@ coremidi = { git = "https://github.com/chris-zen/coremidi.git", rev="fc68464b544
+ fog = { path = "toolkit/components/glean/api" }
+ libudev-sys = { path = "dom/webauthn/libudev-sys" }
+ packed_simd = { package = "packed_simd_2", git = "https://github.com/hsivonen/packed_simd", rev="c149d0a519bf878567c7630096737669ec2ff15f" }
+-midir = { git = "https://github.com/mozilla/midir.git", rev = "4c11f0ffb5d6a10de4aff40a7b81218b33b94e6f" }
+ minidump_writer_linux = { git = "https://github.com/rust-minidump/minidump-writer.git", rev = "75ada456c92a429704691a85e1cb42fef8cafc0d" }
+
+ # application-services overrides to make updating them all simpler.
+diff --git a/README.riscv64.md b/README.riscv64.md
+new file mode 100644
+index 0000000000..705099a3db
+--- /dev/null
++++ b/README.riscv64.md
+@@ -0,0 +1,69 @@
++## Cross building
++I recommend you should use docker environment
++
++#### Dockerfile
++```dockerfile
++FROM ubuntu:21.04
++MAINTAINER Makoto Kato <m_kato@ga2.so-net.ne.jp>
++
++ADD sources.list /etc/apt/
++ENV DEBIAN_FRONTEND=noninteractive
++RUN dpkg --add-architecture riscv64 && \
++ apt-get update && \
++ apt-get install -y clang g++ mercurial g++-riscv64-linux-gnu curl gyp ninja-build make python-is-python3 libssl-dev zlib1g-dev nodejs build-essential libpython3-dev m4 unzip zip uuid git python3-pip && \
++ apt-get install -y zlib1g-dev:riscv64 libssl-dev:riscv64 libffi-dev:riscv64 libasound2-dev:riscv64 libcurl4-openssl-dev:riscv64 libdbus-1-dev:riscv64 libdbus-glib-1-dev:riscv64 libdrm-dev:riscv64 libgtk-3-dev:riscv64 libpulse-dev:riscv64 libx11-xcb-dev:riscv64 libxt-dev:riscv64 xvfb:riscv64 libstdc++-10-dev:riscv64 && \
++ apt-get clean
++WORKDIR /root
++ENV PATH="/root/.cargo/bin:${PATH}"
++RUN curl https://sh.rustup.rs -s -o install.sh && sh install.sh -y && rm install.sh && rustup target add riscv64gc-unknown-linux-gnu
++RUN cargo install cbindgen
++```
++
++#### sources.list
++```
++deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ hirsute main restricted
++deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ hirsute-updates main restricted
++deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ hirsute universe
++deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ hirsute-updates universe
++deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ hirsute multiverse
++deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ hirsute-updates multiverse
++deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ hirsute-backports main restricted universe multiverse
++deb [arch=amd64] http://security.ubuntu.com/ubuntu/ hirsute-security main restricted
++deb [arch=amd64] http://security.ubuntu.com/ubuntu/ hirsute-security universe
++deb [arch=amd64] http://security.ubuntu.com/ubuntu/ hirsute-security multiverse
++
++deb [arch=riscv64] http://ports.ubuntu.com/ubuntu-ports hirsute main restricted
++deb [arch=riscv64] http://ports.ubuntu.com/ubuntu-ports hirsute-updates main restricted
++deb [arch=riscv64] http://ports.ubuntu.com/ubuntu-ports hirsute universe
++deb [arch=riscv64] http://ports.ubuntu.com/ubuntu-ports hirsute-updates universe
++deb [arch=riscv64] http://ports.ubuntu.com/ubuntu-ports hirsute multiverse
++deb [arch=riscv64] http://ports.ubuntu.com/ubuntu-ports hirsute-updates multiverse
++deb [arch=riscv64] http://ports.ubuntu.com/ubuntu-ports hirsute-backports main restricted universe multiverse
++deb [arch=riscv64] http://ports.ubuntu.com/ubuntu-ports hirsute-security main restricted
++deb [arch=riscv64] http://ports.ubuntu.com/ubuntu-ports hirsute-security universe
++deb [arch=riscv64] http://ports.ubuntu.com/ubuntu-ports hirsute-security multiverse
++```
++
++## mozconfig
++```
++mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/objdir
++mk_add_options AUTOCLOBBER=1
++
++ac_add_options --disable-debug
++ac_add_options --enable-optimize
++
++ac_add_options --target=riscv64
++export CC=riscv64-linux-gnu-gcc
++export CXX=riscv64-linux-gnu-g++
++export HOST_CC=gcc
++export HOST_CXX=g++
++ac_add_options --disable-bootstrap
++ac_add_options --without-wasm-sandboxed-libraries
++ac_add_options --enable-webrtc
++ac_add_options --disable-crashreporter
++ac_add_options --disable-jit
++```
++
++## How to build
++1. `./mach build`
++2. `./mach package`
+diff --git a/dom/bindings/moz.build b/dom/bindings/moz.build
+index cf3a8d5017..5e1388cfe5 100644
+--- a/dom/bindings/moz.build
++++ b/dom/bindings/moz.build
+@@ -96,12 +96,16 @@ LOCAL_INCLUDES += [
+ "/layout/xul/tree",
+ "/media/webrtc/",
+ "/netwerk/base/",
+- "/third_party/libwebrtc",
+- "/third_party/libwebrtc/third_party/abseil-cpp",
+ ]
+
+ LOCAL_INCLUDES += ["/third_party/msgpack/include"]
+
++if CONFIG["MOZ_WEBRTC"]:
++ LOCAL_INCLUDES += [
++ "/third_party/libwebrtc",
++ "/third_party/libwebrtc/third_party/abseil-cpp",
++ ]
++
+ DEFINES["GOOGLE_PROTOBUF_NO_RTTI"] = True
+ DEFINES["GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER"] = True
+
+diff --git a/dom/media/gtest/moz.build b/dom/media/gtest/moz.build
+index 05803392cb..d689c7bd77 100644
+--- a/dom/media/gtest/moz.build
++++ b/dom/media/gtest/moz.build
+@@ -13,10 +13,14 @@ LOCAL_INCLUDES += [
+ "/dom/media/systemservices",
+ "/dom/media/webrtc",
+ "/dom/media/webrtc/common",
+- "/third_party/libwebrtc",
+- "/third_party/libwebrtc/third_party/abseil-cpp",
+ ]
+
++if CONFIG["MOZ_WEBRTC"]:
++ LOCAL_INCLUDES += [
++ "/third_party/libwebrtc",
++ "/third_party/libwebrtc/third_party/abseil-cpp",
++ ]
++
+ UNIFIED_SOURCES += [
+ "MockCubeb.cpp",
+ "MockMediaResource.cpp",
+diff --git a/dom/midi/midir_impl/Cargo.toml b/dom/midi/midir_impl/Cargo.toml
+index 7628fb4a68..a918ff2227 100644
+--- a/dom/midi/midir_impl/Cargo.toml
++++ b/dom/midi/midir_impl/Cargo.toml
+@@ -7,7 +7,7 @@ edition = "2018"
+ # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+ [dependencies]
+-midir = "0.7.0"
++midir = "0.8.0"
+ nsstring = { path = "../../../xpcom/rust/nsstring/" }
+ uuid = { version = "0.8", features = ["v4"] }
+ thin-vec = { version = "0.2.1", features = ["gecko-ffi"] }
+diff --git a/ipc/glue/moz.build b/ipc/glue/moz.build
+index c4b7c1d69e..775f553d05 100644
+--- a/ipc/glue/moz.build
++++ b/ipc/glue/moz.build
+@@ -220,6 +220,12 @@ LOCAL_INCLUDES += [
+ "/xpcom/build",
+ ]
+
++if CONFIG["MOZ_WEBRTC"]:
++ LOCAL_INCLUDES += [
++ "/third_party/libwebrtc",
++ "/third_party/libwebrtc/third_party/abseil-cpp",
++ ]
++
+ PREPROCESSED_IPDL_SOURCES = [
+ "PUtilityProcess.ipdl",
+ ]
+diff --git a/js/moz.configure b/js/moz.configure
+index 4f9bb8992f..d53c672aa0 100644
+--- a/js/moz.configure
++++ b/js/moz.configure
+@@ -184,7 +184,7 @@ def report_deprecated(value):
+ # =======================================================
+ option(
+ "--enable-simulator",
+- choices=("arm", "arm64", "mips32", "mips64", "loong64"),
++ choices=("arm", "arm64", "mips32", "mips64", "loong64", "riscv64"),
+ nargs=1,
+ help="Enable a JIT code simulator for the specified architecture",
+ )
+@@ -201,7 +201,7 @@ def simulator(jit_enabled, simulator_enabled, target):
+ if target.cpu != "x86":
+ die("The %s simulator only works on x86." % sim_cpu)
+
+- if sim_cpu in ("arm64", "mips64", "loong64"):
++ if sim_cpu in ("arm64", "mips64", "loong64", "riscv64"):
+ if target.cpu != "x86_64" and target.cpu != "aarch64":
+ die("The %s simulator only works on x86-64 or arm64." % sim_cpu)
+
+@@ -214,12 +214,14 @@ set_config("JS_SIMULATOR_ARM64", simulator.arm64)
+ set_config("JS_SIMULATOR_MIPS32", simulator.mips32)
+ set_config("JS_SIMULATOR_MIPS64", simulator.mips64)
+ set_config("JS_SIMULATOR_LOONG64", simulator.loong64)
++set_config("JS_SIMULATOR_RISCV64", simulator.riscv64)
+ set_define("JS_SIMULATOR", depends_if(simulator)(lambda x: True))
+ set_define("JS_SIMULATOR_ARM", simulator.arm)
+ set_define("JS_SIMULATOR_ARM64", simulator.arm64)
+ set_define("JS_SIMULATOR_MIPS32", simulator.mips32)
+ set_define("JS_SIMULATOR_MIPS64", simulator.mips64)
+ set_define("JS_SIMULATOR_LOONG64", simulator.loong64)
++set_define("JS_SIMULATOR_RISCV64", simulator.riscv64)
+
+
+ @depends("--enable-jit", simulator, target)
+@@ -244,6 +246,7 @@ set_config("JS_CODEGEN_ARM64", jit_codegen.arm64)
+ set_config("JS_CODEGEN_MIPS32", jit_codegen.mips32)
+ set_config("JS_CODEGEN_MIPS64", jit_codegen.mips64)
+ set_config("JS_CODEGEN_LOONG64", jit_codegen.loong64)
++set_config("JS_CODEGEN_RISCV64", jit_codegen.riscv64)
+ set_config("JS_CODEGEN_X86", jit_codegen.x86)
+ set_config("JS_CODEGEN_X64", jit_codegen.x64)
+ set_define("JS_CODEGEN_NONE", jit_codegen.none)
+@@ -252,6 +255,7 @@ set_define("JS_CODEGEN_ARM64", jit_codegen.arm64)
+ set_define("JS_CODEGEN_MIPS32", jit_codegen.mips32)
+ set_define("JS_CODEGEN_MIPS64", jit_codegen.mips64)
+ set_define("JS_CODEGEN_LOONG64", jit_codegen.loong64)
++set_define("JS_CODEGEN_RISCV64", jit_codegen.riscv64)
+ set_define("JS_CODEGEN_X86", jit_codegen.x86)
+ set_define("JS_CODEGEN_X64", jit_codegen.x64)
+
+diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp
+index 2b8de6284f..1b9b4b62c7 100644
+--- a/js/src/builtin/TestingFunctions.cpp
++++ b/js/src/builtin/TestingFunctions.cpp
+@@ -426,6 +426,24 @@ static bool GetBuildConfiguration(JSContext* cx, unsigned argc, Value* vp) {
+ return false;
+ }
+
++#ifdef JS_CODEGEN_RISCV64
++ value = BooleanValue(true);
++#else
++ value = BooleanValue(false);
++#endif
++ if (!JS_SetProperty(cx, info, "riscv64", value)) {
++ return false;
++ }
++
++#ifdef JS_SIMULATOR_RISCV64
++ value = BooleanValue(true);
++#else
++ value = BooleanValue(false);
++#endif
++ if (!JS_SetProperty(cx, info, "riscv64-simulator", value)) {
++ return false;
++ }
++
+ #ifdef JS_SIMULATOR
+ value = BooleanValue(true);
+ #else
+diff --git a/js/src/jit/Assembler.h b/js/src/jit/Assembler.h
+index 04dcdc647e..2081f254b0 100644
+--- a/js/src/jit/Assembler.h
++++ b/js/src/jit/Assembler.h
+@@ -19,6 +19,8 @@
+ # include "jit/mips32/Assembler-mips32.h"
+ #elif defined(JS_CODEGEN_MIPS64)
+ # include "jit/mips64/Assembler-mips64.h"
++#elif defined(JS_CODEGEN_RISCV64)
++# include "jit/riscv64/Assembler-riscv64.h"
+ #elif defined(JS_CODEGEN_LOONG64)
+ # include "jit/loong64/Assembler-loong64.h"
+ #elif defined(JS_CODEGEN_NONE)
+diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h
+index 67453d3cd3..82e58d2a16 100644
+--- a/js/src/jit/CodeGenerator.h
++++ b/js/src/jit/CodeGenerator.h
+@@ -26,6 +26,8 @@
+ # include "jit/mips64/CodeGenerator-mips64.h"
+ #elif defined(JS_CODEGEN_LOONG64)
+ # include "jit/loong64/CodeGenerator-loong64.h"
++#elif defined(JS_CODEGEN_RISCV64)
++# include "jit/riscv64/CodeGenerator-riscv64.h"
+ #elif defined(JS_CODEGEN_NONE)
+ # include "jit/none/CodeGenerator-none.h"
+ #else
+diff --git a/js/src/jit/FlushICache.h b/js/src/jit/FlushICache.h
+index 42b1fb045c..feeae3c793 100644
+--- a/js/src/jit/FlushICache.h
++++ b/js/src/jit/FlushICache.h
+@@ -25,7 +25,7 @@ inline void FlushICache(void* code, size_t size,
+
+ #elif (defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)) || \
+ (defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)) || \
+- defined(JS_CODEGEN_LOONG64)
++ defined(JS_CODEGEN_LOONG64) || defined(JS_CODEGEN_RISCV64)
+
+ extern void FlushICache(void* code, size_t size, bool codeIsThreadLocal = true);
+
+diff --git a/js/src/jit/LIR.h b/js/src/jit/LIR.h
+index 66c665b5ba..016c8246f7 100644
+--- a/js/src/jit/LIR.h
++++ b/js/src/jit/LIR.h
+@@ -1933,6 +1933,8 @@ AnyRegister LAllocation::toRegister() const {
+ # include "jit/mips64/LIR-mips64.h"
+ # endif
+ # include "jit/mips-shared/LIR-mips-shared.h"
++#elif defined(JS_CODEGEN_RISCV64)
++# include "jit/riscv64/LIR-riscv64.h"
+ #elif defined(JS_CODEGEN_NONE)
+ # include "jit/none/LIR-none.h"
+ #else
+diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h
+index a04d09c446..21094a616e 100644
+--- a/js/src/jit/Lowering.h
++++ b/js/src/jit/Lowering.h
+@@ -23,6 +23,8 @@
+ # include "jit/mips32/Lowering-mips32.h"
+ #elif defined(JS_CODEGEN_MIPS64)
+ # include "jit/mips64/Lowering-mips64.h"
++#elif defined(JS_CODEGEN_RISCV64)
++# include "jit/riscv64/Lowering-riscv64.h"
+ #elif defined(JS_CODEGEN_LOONG64)
+ # include "jit/loong64/Lowering-loong64.h"
+ #elif defined(JS_CODEGEN_NONE)
+diff --git a/js/src/jit/MacroAssembler-inl.h b/js/src/jit/MacroAssembler-inl.h
+index 5ed4ac7458..1c208e676d 100644
+--- a/js/src/jit/MacroAssembler-inl.h
++++ b/js/src/jit/MacroAssembler-inl.h
+@@ -39,6 +39,8 @@
+ # include "jit/mips64/MacroAssembler-mips64-inl.h"
+ #elif defined(JS_CODEGEN_LOONG64)
+ # include "jit/loong64/MacroAssembler-loong64-inl.h"
++#elif defined(JS_CODEGEN_RISCV64)
++# include "jit/riscv64/MacroAssembler-riscv64-inl.h"
+ #elif !defined(JS_CODEGEN_NONE)
+ # error "Unknown architecture!"
+ #endif
+diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp
+index 3abc601bec..0665601509 100644
+--- a/js/src/jit/MacroAssembler.cpp
++++ b/js/src/jit/MacroAssembler.cpp
+@@ -4145,6 +4145,8 @@ void MacroAssembler::emitPreBarrierFastPath(JSRuntime* rt, MIRType type,
+ ma_dsll(temp1, temp1, temp3);
+ #elif JS_CODEGEN_LOONG64
+ as_sll_d(temp1, temp1, temp3);
++#elif JS_CODEGEN_RISCV64
++ MOZ_CRASH();
+ #elif JS_CODEGEN_NONE
+ MOZ_CRASH();
+ #else
+diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h
+index 5fa8f40bd1..3395a139d3 100644
+--- a/js/src/jit/MacroAssembler.h
++++ b/js/src/jit/MacroAssembler.h
+@@ -25,6 +25,8 @@
+ # include "jit/mips32/MacroAssembler-mips32.h"
+ #elif defined(JS_CODEGEN_MIPS64)
+ # include "jit/mips64/MacroAssembler-mips64.h"
++#elif defined(JS_CODEGEN_RISCV64)
++# include "jit/riscv64/MacroAssembler-riscv64.h"
+ #elif defined(JS_CODEGEN_LOONG64)
+ # include "jit/loong64/MacroAssembler-loong64.h"
+ #elif defined(JS_CODEGEN_NONE)
+@@ -94,8 +96,8 @@
+ // }
+ // ////}}} check_macroassembler_style
+
+-#define ALL_ARCH mips32, mips64, arm, arm64, x86, x64, loong64
+-#define ALL_SHARED_ARCH arm, arm64, loong64, x86_shared, mips_shared
++#define ALL_ARCH mips32, mips64, arm, arm64, x86, x64, loong64, riscv64
++#define ALL_SHARED_ARCH arm, arm64, loong64, riscv64, x86_shared, mips_shared
+
+ // * How this macro works:
+ //
+@@ -142,6 +144,7 @@
+ #define DEFINED_ON_mips64
+ #define DEFINED_ON_mips_shared
+ #define DEFINED_ON_loong64
++#define DEFINED_ON_riscv64
+ #define DEFINED_ON_none
+
+ // Specialize for each architecture.
+@@ -174,6 +177,9 @@
+ #elif defined(JS_CODEGEN_LOONG64)
+ # undef DEFINED_ON_loong64
+ # define DEFINED_ON_loong64 define
++#elif defined(JS_CODEGEN_RISCV64)
++# undef DEFINED_ON_riscv64
++# define DEFINED_ON_riscv64 define
+ #elif defined(JS_CODEGEN_NONE)
+ # undef DEFINED_ON_none
+ # define DEFINED_ON_none crash
+@@ -491,10 +497,10 @@ class MacroAssembler : public MacroAssemblerSpecific {
+
+ // The size of the area used by PushRegsInMask.
+ size_t PushRegsInMaskSizeInBytes(LiveRegisterSet set)
+- DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared);
++ DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared, riscv64);
+
+ void PushRegsInMask(LiveRegisterSet set)
+- DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared);
++ DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared, riscv64);
+ void PushRegsInMask(LiveGeneralRegisterSet set);
+
+ // Like PushRegsInMask, but instead of pushing the registers, store them to
+@@ -505,12 +511,12 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ // must point to either the lowest address in the save area, or some address
+ // below that.
+ void storeRegsInMask(LiveRegisterSet set, Address dest, Register scratch)
+- DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared);
++ DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared, riscv64);
+
+ void PopRegsInMask(LiveRegisterSet set);
+ void PopRegsInMask(LiveGeneralRegisterSet set);
+ void PopRegsInMaskIgnore(LiveRegisterSet set, LiveRegisterSet ignore)
+- DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared);
++ DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared, riscv64);
+
+ // ===============================================================
+ // Stack manipulation functions -- single registers/values.
+@@ -543,7 +549,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ void Pop(FloatRegister t) PER_SHARED_ARCH;
+ void Pop(const ValueOperand& val) PER_SHARED_ARCH;
+ void PopFlags() DEFINED_ON(x86_shared);
+- void PopStackPtr() DEFINED_ON(arm, mips_shared, x86_shared, loong64);
++ void PopStackPtr() DEFINED_ON(arm, mips_shared, x86_shared, loong64, riscv64);
+ void popRooted(VMFunctionData::RootType rootType, Register cellReg,
+ const ValueOperand& valueReg);
+
+@@ -601,8 +607,9 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ void callAndPushReturnAddress(Label* label) DEFINED_ON(x86_shared);
+
+ // These do not adjust framePushed().
+- void pushReturnAddress() DEFINED_ON(mips_shared, arm, arm64, loong64);
+- void popReturnAddress() DEFINED_ON(mips_shared, arm, arm64, loong64);
++ void pushReturnAddress()
++ DEFINED_ON(mips_shared, arm, arm64, loong64, riscv64);
++ void popReturnAddress() DEFINED_ON(mips_shared, arm, arm64, loong64, riscv64);
+
+ // Useful for dealing with two-valued returns.
+ void moveRegPair(Register src0, Register src1, Register dst0, Register dst1,
+@@ -633,10 +640,10 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ // Note: "Near" applies to ARM64 where the target must be within 1 MB (this is
+ // release-asserted).
+ CodeOffset moveNearAddressWithPatch(Register dest)
+- DEFINED_ON(x86, x64, arm, arm64, loong64, mips_shared);
++ DEFINED_ON(x86, x64, arm, arm64, loong64, mips_shared, riscv64);
+ static void patchNearAddressMove(CodeLocationLabel loc,
+ CodeLocationLabel target)
+- DEFINED_ON(x86, x64, arm, arm64, loong64, mips_shared);
++ DEFINED_ON(x86, x64, arm, arm64, loong64, mips_shared, riscv64);
+
+ public:
+ // ===============================================================
+@@ -1045,17 +1052,17 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ inline void addPtr(ImmWord imm, Register dest) PER_ARCH;
+ inline void addPtr(ImmPtr imm, Register dest);
+ inline void addPtr(Imm32 imm, const Address& dest)
+- DEFINED_ON(mips_shared, arm, arm64, x86, x64, loong64);
++ DEFINED_ON(mips_shared, arm, arm64, x86, x64, loong64, riscv64);
+ inline void addPtr(Imm32 imm, const AbsoluteAddress& dest)
+ DEFINED_ON(x86, x64);
+ inline void addPtr(const Address& src, Register dest)
+- DEFINED_ON(mips_shared, arm, arm64, x86, x64, loong64);
++ DEFINED_ON(mips_shared, arm, arm64, x86, x64, loong64, riscv64);
+
+ inline void add64(Register64 src, Register64 dest) PER_ARCH;
+ inline void add64(Imm32 imm, Register64 dest) PER_ARCH;
+ inline void add64(Imm64 imm, Register64 dest) PER_ARCH;
+ inline void add64(const Operand& src, Register64 dest)
+- DEFINED_ON(x64, mips64, loong64);
++ DEFINED_ON(x64, mips64, loong64, riscv64);
+
+ inline void addFloat32(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH;
+
+@@ -1074,16 +1081,16 @@ class MacroAssembler : public MacroAssemblerSpecific {
+
+ inline void subPtr(Register src, Register dest) PER_ARCH;
+ inline void subPtr(Register src, const Address& dest)
+- DEFINED_ON(mips_shared, arm, arm64, x86, x64, loong64);
++ DEFINED_ON(mips_shared, arm, arm64, x86, x64, loong64, riscv64);
+ inline void subPtr(Imm32 imm, Register dest) PER_ARCH;
+ inline void subPtr(ImmWord imm, Register dest) DEFINED_ON(x64);
+ inline void subPtr(const Address& addr, Register dest)
+- DEFINED_ON(mips_shared, arm, arm64, x86, x64, loong64);
++ DEFINED_ON(mips_shared, arm, arm64, x86, x64, loong64, riscv64);
+
+ inline void sub64(Register64 src, Register64 dest) PER_ARCH;
+ inline void sub64(Imm64 imm, Register64 dest) PER_ARCH;
+ inline void sub64(const Operand& src, Register64 dest)
+- DEFINED_ON(x64, mips64, loong64);
++ DEFINED_ON(x64, mips64, loong64, riscv64);
+
+ inline void subFloat32(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH;
+
+@@ -1099,10 +1106,11 @@ class MacroAssembler : public MacroAssemblerSpecific {
+
+ inline void mul64(const Operand& src, const Register64& dest) DEFINED_ON(x64);
+ inline void mul64(const Operand& src, const Register64& dest,
+- const Register temp) DEFINED_ON(x64, mips64, loong64);
++ const Register temp)
++ DEFINED_ON(x64, mips64, loong64, riscv64);
+ inline void mul64(Imm64 imm, const Register64& dest) PER_ARCH;
+ inline void mul64(Imm64 imm, const Register64& dest, const Register temp)
+- DEFINED_ON(x86, x64, arm, mips32, mips64, loong64);
++ DEFINED_ON(x86, x64, arm, mips32, mips64, loong64, riscv64);
+ inline void mul64(const Register64& src, const Register64& dest,
+ const Register temp) PER_ARCH;
+ inline void mul64(const Register64& src1, const Register64& src2,
+@@ -1116,14 +1124,14 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ inline void mulDouble(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH;
+
+ inline void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest)
+- DEFINED_ON(mips_shared, arm, arm64, x86, x64, loong64);
++ DEFINED_ON(mips_shared, arm, arm64, x86, x64, loong64, riscv64);
+
+ // Perform an integer division, returning the integer part rounded toward
+ // zero. rhs must not be zero, and the division must not overflow.
+ //
+ // On ARM, the chip must have hardware division instructions.
+ inline void quotient32(Register rhs, Register srcDest, bool isUnsigned)
+- DEFINED_ON(mips_shared, arm, arm64, loong64);
++ DEFINED_ON(mips_shared, arm, arm64, loong64, riscv64);
+
+ // As above, but srcDest must be eax and tempEdx must be edx.
+ inline void quotient32(Register rhs, Register srcDest, Register tempEdx,
+@@ -1134,7 +1142,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ //
+ // On ARM, the chip must have hardware division instructions.
+ inline void remainder32(Register rhs, Register srcDest, bool isUnsigned)
+- DEFINED_ON(mips_shared, arm, arm64, loong64);
++ DEFINED_ON(mips_shared, arm, arm64, loong64, riscv64);
+
+ // As above, but srcDest must be eax and tempEdx must be edx.
+ inline void remainder32(Register rhs, Register srcDest, Register tempEdx,
+@@ -1149,7 +1157,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ // rhs is preserved, srdDest is clobbered.
+ void flexibleRemainder32(Register rhs, Register srcDest, bool isUnsigned,
+ const LiveRegisterSet& volatileLiveRegs)
+- DEFINED_ON(mips_shared, arm, arm64, x86_shared, loong64);
++ DEFINED_ON(mips_shared, arm, arm64, x86_shared, loong64, riscv64);
+
+ // Perform an integer division, returning the integer part rounded toward
+ // zero. rhs must not be zero, and the division must not overflow.
+@@ -1160,7 +1168,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ // rhs is preserved, srdDest is clobbered.
+ void flexibleQuotient32(Register rhs, Register srcDest, bool isUnsigned,
+ const LiveRegisterSet& volatileLiveRegs)
+- DEFINED_ON(mips_shared, arm, arm64, x86_shared, loong64);
++ DEFINED_ON(mips_shared, arm, arm64, x86_shared, loong64, riscv64);
+
+ // Perform an integer division, returning the integer part rounded toward
+ // zero. rhs must not be zero, and the division must not overflow. The
+@@ -1173,7 +1181,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ void flexibleDivMod32(Register rhs, Register srcDest, Register remOutput,
+ bool isUnsigned,
+ const LiveRegisterSet& volatileLiveRegs)
+- DEFINED_ON(mips_shared, arm, arm64, x86_shared, loong64);
++ DEFINED_ON(mips_shared, arm, arm64, x86_shared, loong64, riscv64);
+
+ inline void divFloat32(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH;
+ inline void divDouble(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH;
+@@ -1380,7 +1388,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+
+ template <typename T1, typename T2>
+ inline void cmp32Set(Condition cond, T1 lhs, T2 rhs, Register dest)
+- DEFINED_ON(x86_shared, arm, arm64, mips32, mips64, loong64);
++ DEFINED_ON(x86_shared, arm, arm64, mips32, mips64, loong64, riscv64);
+
+ // Only the NotEqual and Equal conditions are allowed.
+ inline void cmp64Set(Condition cond, Address lhs, Imm64 rhs,
+@@ -1415,10 +1423,10 @@ class MacroAssembler : public MacroAssemblerSpecific {
+
+ inline void branch32(Condition cond, const AbsoluteAddress& lhs, Register rhs,
+ Label* label)
+- DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64);
++ DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64, riscv64);
+ inline void branch32(Condition cond, const AbsoluteAddress& lhs, Imm32 rhs,
+ Label* label)
+- DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64);
++ DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64, riscv64);
+
+ inline void branch32(Condition cond, const BaseIndex& lhs, Register rhs,
+ Label* label) DEFINED_ON(arm, x86_shared);
+@@ -1432,7 +1440,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+
+ inline void branch32(Condition cond, wasm::SymbolicAddress lhs, Imm32 rhs,
+ Label* label)
+- DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64);
++ DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64, riscv64);
+
+ // The supported condition are Equal, NotEqual, LessThan(orEqual),
+ // GreaterThan(orEqual), Below(orEqual) and Above(orEqual). When a fail label
+@@ -1483,14 +1491,14 @@ class MacroAssembler : public MacroAssemblerSpecific {
+
+ inline void branchPtr(Condition cond, const AbsoluteAddress& lhs,
+ Register rhs, Label* label)
+- DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64);
++ DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64, riscv64);
+ inline void branchPtr(Condition cond, const AbsoluteAddress& lhs, ImmWord rhs,
+ Label* label)
+- DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64);
++ DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64, riscv64);
+
+ inline void branchPtr(Condition cond, wasm::SymbolicAddress lhs, Register rhs,
+ Label* label)
+- DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64);
++ DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64, riscv64);
+
+ // Given a pointer to a GC Cell, retrieve the StoreBuffer pointer from its
+ // chunk header, or nullptr if it is in the tenured heap.
+@@ -1498,7 +1506,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+
+ void branchPtrInNurseryChunk(Condition cond, Register ptr, Register temp,
+ Label* label)
+- DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64);
++ DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64, riscv64);
+ void branchPtrInNurseryChunk(Condition cond, const Address& address,
+ Register temp, Label* label) DEFINED_ON(x86);
+ void branchValueIsNurseryCell(Condition cond, const Address& address,
+@@ -1520,10 +1528,10 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ // x64 variants will do this only in the int64_t range.
+ inline void branchTruncateFloat32MaybeModUint32(FloatRegister src,
+ Register dest, Label* fail)
+- DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64);
++ DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64, riscv64);
+ inline void branchTruncateDoubleMaybeModUint32(FloatRegister src,
+ Register dest, Label* fail)
+- DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64);
++ DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64, riscv64);
+
+ // Truncate a double/float32 to intptr and when it doesn't fit jump to the
+ // failure label.
+@@ -1536,10 +1544,10 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ // failure label.
+ inline void branchTruncateFloat32ToInt32(FloatRegister src, Register dest,
+ Label* fail)
+- DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64);
++ DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64, riscv64);
+ inline void branchTruncateDoubleToInt32(FloatRegister src, Register dest,
+ Label* fail)
+- DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64);
++ DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64, riscv64);
+
+ inline void branchDouble(DoubleCondition cond, FloatRegister lhs,
+ FloatRegister rhs, Label* label) PER_SHARED_ARCH;
+@@ -1596,7 +1604,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ Label* label) PER_SHARED_ARCH;
+ inline void branchTest32(Condition cond, const AbsoluteAddress& lhs,
+ Imm32 rhs, Label* label)
+- DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64);
++ DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64, riscv64);
+
+ template <class L>
+ inline void branchTestPtr(Condition cond, Register lhs, Register rhs,
+@@ -1757,7 +1765,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ inline void branchTestInt32(Condition cond, Register tag,
+ Label* label) PER_SHARED_ARCH;
+ inline void branchTestDouble(Condition cond, Register tag, Label* label)
+- DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared);
++ DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared, riscv64);
+ inline void branchTestNumber(Condition cond, Register tag,
+ Label* label) PER_SHARED_ARCH;
+ inline void branchTestBoolean(Condition cond, Register tag,
+@@ -1789,7 +1797,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ Label* label) PER_SHARED_ARCH;
+ inline void branchTestUndefined(Condition cond, const ValueOperand& value,
+ Label* label)
+- DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared);
++ DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared, riscv64);
+
+ inline void branchTestInt32(Condition cond, const Address& address,
+ Label* label) PER_SHARED_ARCH;
+@@ -1797,7 +1805,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ Label* label) PER_SHARED_ARCH;
+ inline void branchTestInt32(Condition cond, const ValueOperand& value,
+ Label* label)
+- DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared);
++ DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared, riscv64);
+
+ inline void branchTestDouble(Condition cond, const Address& address,
+ Label* label) PER_SHARED_ARCH;
+@@ -1805,11 +1813,11 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ Label* label) PER_SHARED_ARCH;
+ inline void branchTestDouble(Condition cond, const ValueOperand& value,
+ Label* label)
+- DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared);
++ DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared, riscv64);
+
+ inline void branchTestNumber(Condition cond, const ValueOperand& value,
+ Label* label)
+- DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared);
++ DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared, riscv64);
+
+ inline void branchTestBoolean(Condition cond, const Address& address,
+ Label* label) PER_SHARED_ARCH;
+@@ -1817,7 +1825,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ Label* label) PER_SHARED_ARCH;
+ inline void branchTestBoolean(Condition cond, const ValueOperand& value,
+ Label* label)
+- DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared);
++ DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared, riscv64);
+
+ inline void branchTestString(Condition cond, const Address& address,
+ Label* label) PER_SHARED_ARCH;
+@@ -1825,7 +1833,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ Label* label) PER_SHARED_ARCH;
+ inline void branchTestString(Condition cond, const ValueOperand& value,
+ Label* label)
+- DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared);
++ DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared, riscv64);
+
+ inline void branchTestSymbol(Condition cond, const Address& address,
+ Label* label) PER_SHARED_ARCH;
+@@ -1833,7 +1841,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ Label* label) PER_SHARED_ARCH;
+ inline void branchTestSymbol(Condition cond, const ValueOperand& value,
+ Label* label)
+- DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared);
++ DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared, riscv64);
+
+ inline void branchTestBigInt(Condition cond, const Address& address,
+ Label* label) PER_SHARED_ARCH;
+@@ -1841,7 +1849,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ Label* label) PER_SHARED_ARCH;
+ inline void branchTestBigInt(Condition cond, const ValueOperand& value,
+ Label* label)
+- DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared);
++ DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared, riscv64);
+
+ inline void branchTestNull(Condition cond, const Address& address,
+ Label* label) PER_SHARED_ARCH;
+@@ -1849,7 +1857,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ Label* label) PER_SHARED_ARCH;
+ inline void branchTestNull(Condition cond, const ValueOperand& value,
+ Label* label)
+- DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared);
++ DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared, riscv64);
+
+ // Clobbers the ScratchReg on x64.
+ inline void branchTestObject(Condition cond, const Address& address,
+@@ -1858,7 +1866,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ Label* label) PER_SHARED_ARCH;
+ inline void branchTestObject(Condition cond, const ValueOperand& value,
+ Label* label)
+- DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared);
++ DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared, riscv64);
+
+ inline void branchTestGCThing(Condition cond, const Address& address,
+ Label* label) PER_SHARED_ARCH;
+@@ -1869,7 +1877,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+
+ inline void branchTestPrimitive(Condition cond, const ValueOperand& value,
+ Label* label)
+- DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared);
++ DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared, riscv64);
+
+ inline void branchTestMagic(Condition cond, const Address& address,
+ Label* label) PER_SHARED_ARCH;
+@@ -1878,7 +1886,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ template <class L>
+ inline void branchTestMagic(Condition cond, const ValueOperand& value,
+ L label)
+- DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared);
++ DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared, riscv64);
+
+ inline void branchTestMagic(Condition cond, const Address& valaddr,
+ JSWhyMagic why, Label* label) PER_ARCH;
+@@ -1896,17 +1904,17 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ // The type of the value should match the type of the method.
+ inline void branchTestInt32Truthy(bool truthy, const ValueOperand& value,
+ Label* label)
+- DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared);
++ DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared, riscv64);
+ inline void branchTestDoubleTruthy(bool truthy, FloatRegister reg,
+ Label* label) PER_SHARED_ARCH;
+ inline void branchTestBooleanTruthy(bool truthy, const ValueOperand& value,
+ Label* label) PER_ARCH;
+ inline void branchTestStringTruthy(bool truthy, const ValueOperand& value,
+ Label* label)
+- DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared);
++ DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared, riscv64);
+ inline void branchTestBigIntTruthy(bool truthy, const ValueOperand& value,
+ Label* label)
+- DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared);
++ DEFINED_ON(arm, arm64, mips32, mips64, loong64, x86_shared, riscv64);
+
+ // Create an unconditional branch to the address given as argument.
+ inline void branchToComputedAddress(const BaseIndex& address) PER_ARCH;
+@@ -2008,11 +2016,11 @@ class MacroAssembler : public MacroAssemblerSpecific {
+
+ inline void cmp32Move32(Condition cond, Register lhs, Register rhs,
+ Register src, Register dest)
+- DEFINED_ON(arm, arm64, loong64, mips_shared, x86_shared);
++ DEFINED_ON(arm, arm64, loong64, mips_shared, x86_shared, riscv64);
+
+ inline void cmp32Move32(Condition cond, Register lhs, const Address& rhs,
+ Register src, Register dest)
+- DEFINED_ON(arm, arm64, loong64, mips_shared, x86_shared);
++ DEFINED_ON(arm, arm64, loong64, mips_shared, x86_shared, riscv64);
+
+ inline void cmpPtrMovePtr(Condition cond, Register lhs, Register rhs,
+ Register src, Register dest) PER_ARCH;
+@@ -2022,36 +2030,36 @@ class MacroAssembler : public MacroAssemblerSpecific {
+
+ inline void cmp32Load32(Condition cond, Register lhs, const Address& rhs,
+ const Address& src, Register dest)
+- DEFINED_ON(arm, arm64, loong64, mips_shared, x86_shared);
++ DEFINED_ON(arm, arm64, loong64, mips_shared, x86_shared, riscv64);
+
+ inline void cmp32Load32(Condition cond, Register lhs, Register rhs,
+ const Address& src, Register dest)
+- DEFINED_ON(arm, arm64, loong64, mips_shared, x86_shared);
++ DEFINED_ON(arm, arm64, loong64, mips_shared, x86_shared, riscv64);
+
+ inline void cmp32LoadPtr(Condition cond, const Address& lhs, Imm32 rhs,
+ const Address& src, Register dest)
+- DEFINED_ON(arm, arm64, loong64, mips_shared, x86, x64);
++ DEFINED_ON(arm, arm64, loong64, mips_shared, x86, x64, riscv64);
+
+ inline void cmp32MovePtr(Condition cond, Register lhs, Imm32 rhs,
+ Register src, Register dest)
+- DEFINED_ON(arm, arm64, loong64, mips_shared, x86, x64);
++ DEFINED_ON(arm, arm64, loong64, mips_shared, x86, x64, riscv64);
+
+ inline void test32LoadPtr(Condition cond, const Address& addr, Imm32 mask,
+ const Address& src, Register dest)
+- DEFINED_ON(arm, arm64, loong64, mips_shared, x86, x64);
++ DEFINED_ON(arm, arm64, loong64, mips_shared, x86, x64, riscv64);
+
+ inline void test32MovePtr(Condition cond, const Address& addr, Imm32 mask,
+ Register src, Register dest)
+- DEFINED_ON(arm, arm64, loong64, mips_shared, x86, x64);
++ DEFINED_ON(arm, arm64, loong64, mips_shared, x86, x64, riscv64);
+
+ // Conditional move for Spectre mitigations.
+ inline void spectreMovePtr(Condition cond, Register src, Register dest)
+- DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64);
++ DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64, riscv64);
+
+ // Zeroes dest if the condition is true.
+ inline void spectreZeroRegister(Condition cond, Register scratch,
+ Register dest)
+- DEFINED_ON(arm, arm64, mips_shared, x86_shared, loong64);
++ DEFINED_ON(arm, arm64, mips_shared, x86_shared, loong64, riscv64);
+
+ // Performs a bounds check and zeroes the index register if out-of-bounds
+ // (to mitigate Spectre).
+@@ -2063,17 +2071,17 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ public:
+ inline void spectreBoundsCheck32(Register index, Register length,
+ Register maybeScratch, Label* failure)
+- DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64);
++ DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64, riscv64);
+ inline void spectreBoundsCheck32(Register index, const Address& length,
+ Register maybeScratch, Label* failure)
+- DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64);
++ DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64, riscv64);
+
+ inline void spectreBoundsCheckPtr(Register index, Register length,
+ Register maybeScratch, Label* failure)
+- DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64);
++ DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64, riscv64);
+ inline void spectreBoundsCheckPtr(Register index, const Address& length,
+ Register maybeScratch, Label* failure)
+- DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64);
++ DEFINED_ON(arm, arm64, mips_shared, x86, x64, loong64, riscv64);
+
+ // ========================================================================
+ // Canonicalization primitives.
+@@ -2087,10 +2095,10 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ // ========================================================================
+ // Memory access primitives.
+ inline void storeUncanonicalizedDouble(FloatRegister src, const Address& dest)
+- DEFINED_ON(x86_shared, arm, arm64, mips32, mips64, loong64);
++ DEFINED_ON(x86_shared, arm, arm64, mips32, mips64, loong64, riscv64);
+ inline void storeUncanonicalizedDouble(FloatRegister src,
+ const BaseIndex& dest)
+- DEFINED_ON(x86_shared, arm, arm64, mips32, mips64, loong64);
++ DEFINED_ON(x86_shared, arm, arm64, mips32, mips64, loong64, riscv64);
+ inline void storeUncanonicalizedDouble(FloatRegister src, const Operand& dest)
+ DEFINED_ON(x86_shared);
+
+@@ -2104,10 +2112,10 @@ class MacroAssembler : public MacroAssemblerSpecific {
+
+ inline void storeUncanonicalizedFloat32(FloatRegister src,
+ const Address& dest)
+- DEFINED_ON(x86_shared, arm, arm64, mips32, mips64, loong64);
++ DEFINED_ON(x86_shared, arm, arm64, mips32, mips64, loong64, riscv64);
+ inline void storeUncanonicalizedFloat32(FloatRegister src,
+ const BaseIndex& dest)
+- DEFINED_ON(x86_shared, arm, arm64, mips32, mips64, loong64);
++ DEFINED_ON(x86_shared, arm, arm64, mips32, mips64, loong64, riscv64);
+ inline void storeUncanonicalizedFloat32(FloatRegister src,
+ const Operand& dest)
+ DEFINED_ON(x86_shared);
+@@ -3508,10 +3516,10 @@ class MacroAssembler : public MacroAssemblerSpecific {
+
+ // temp required on x86 and x64; must be undefined on mips64 and loong64.
+ void convertUInt64ToFloat32(Register64 src, FloatRegister dest, Register temp)
+- DEFINED_ON(arm64, mips64, loong64, x64, x86);
++ DEFINED_ON(arm64, mips64, loong64, x64, x86, riscv64);
+
+ void convertInt64ToFloat32(Register64 src, FloatRegister dest)
+- DEFINED_ON(arm64, mips64, loong64, x64, x86);
++ DEFINED_ON(arm64, mips64, loong64, x64, x86, riscv64);
+
+ bool convertUInt64ToDoubleNeedsTemp() PER_ARCH;
+
+@@ -3563,19 +3571,19 @@ class MacroAssembler : public MacroAssemblerSpecific {
+
+ void wasmBoundsCheck32(Condition cond, Register index,
+ Register boundsCheckLimit, Label* ok)
+- DEFINED_ON(arm, arm64, mips32, mips64, x86_shared, loong64);
++ DEFINED_ON(arm, arm64, mips32, mips64, x86_shared, loong64, riscv64);
+
+ void wasmBoundsCheck32(Condition cond, Register index,
+ Address boundsCheckLimit, Label* ok)
+- DEFINED_ON(arm, arm64, mips32, mips64, x86_shared, loong64);
++ DEFINED_ON(arm, arm64, mips32, mips64, x86_shared, loong64, riscv64);
+
+ void wasmBoundsCheck64(Condition cond, Register64 index,
+ Register64 boundsCheckLimit, Label* ok)
+- DEFINED_ON(arm64, mips64, x64, x86, arm, loong64);
++ DEFINED_ON(arm64, mips64, x64, x86, arm, loong64, riscv64);
+
+ void wasmBoundsCheck64(Condition cond, Register64 index,
+ Address boundsCheckLimit, Label* ok)
+- DEFINED_ON(arm64, mips64, x64, x86, arm, loong64);
++ DEFINED_ON(arm64, mips64, x64, x86, arm, loong64, riscv64);
+
+ // Each wasm load/store instruction appends its own wasm::Trap::OutOfBounds.
+ void wasmLoad(const wasm::MemoryAccessDesc& access, Operand srcAddr,
+@@ -3668,7 +3676,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ void oolWasmTruncateCheckF64ToI32(FloatRegister input, Register output,
+ TruncFlags flags, wasm::BytecodeOffset off,
+ Label* rejoin)
+- DEFINED_ON(arm, arm64, x86_shared, mips_shared, loong64);
++ DEFINED_ON(arm, arm64, x86_shared, mips_shared, loong64, riscv64);
+
+ void wasmTruncateFloat32ToUInt32(FloatRegister input, Register output,
+ bool isSaturating, Label* oolEntry) PER_ARCH;
+@@ -3678,35 +3686,35 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ void oolWasmTruncateCheckF32ToI32(FloatRegister input, Register output,
+ TruncFlags flags, wasm::BytecodeOffset off,
+ Label* rejoin)
+- DEFINED_ON(arm, arm64, x86_shared, mips_shared, loong64);
++ DEFINED_ON(arm, arm64, x86_shared, mips_shared, loong64, riscv64);
+
+ // The truncate-to-int64 methods will always bind the `oolRejoin` label
+ // after the last emitted instruction.
+ void wasmTruncateDoubleToInt64(FloatRegister input, Register64 output,
+ bool isSaturating, Label* oolEntry,
+ Label* oolRejoin, FloatRegister tempDouble)
+- DEFINED_ON(arm64, x86, x64, mips64, loong64);
++ DEFINED_ON(arm64, x86, x64, mips64, loong64, riscv64);
+ void wasmTruncateDoubleToUInt64(FloatRegister input, Register64 output,
+ bool isSaturating, Label* oolEntry,
+ Label* oolRejoin, FloatRegister tempDouble)
+- DEFINED_ON(arm64, x86, x64, mips64, loong64);
++ DEFINED_ON(arm64, x86, x64, mips64, loong64, riscv64);
+ void oolWasmTruncateCheckF64ToI64(FloatRegister input, Register64 output,
+ TruncFlags flags, wasm::BytecodeOffset off,
+ Label* rejoin)
+- DEFINED_ON(arm, arm64, x86_shared, mips_shared, loong64);
++ DEFINED_ON(arm, arm64, x86_shared, mips_shared, loong64, riscv64);
+
+ void wasmTruncateFloat32ToInt64(FloatRegister input, Register64 output,
+ bool isSaturating, Label* oolEntry,
+ Label* oolRejoin, FloatRegister tempDouble)
+- DEFINED_ON(arm64, x86, x64, mips64, loong64);
++ DEFINED_ON(arm64, x86, x64, mips64, loong64, riscv64);
+ void wasmTruncateFloat32ToUInt64(FloatRegister input, Register64 output,
+ bool isSaturating, Label* oolEntry,
+ Label* oolRejoin, FloatRegister tempDouble)
+- DEFINED_ON(arm64, x86, x64, mips64, loong64);
++ DEFINED_ON(arm64, x86, x64, mips64, loong64, riscv64);
+ void oolWasmTruncateCheckF32ToI64(FloatRegister input, Register64 output,
+ TruncFlags flags, wasm::BytecodeOffset off,
+ Label* rejoin)
+- DEFINED_ON(arm, arm64, x86_shared, mips_shared, loong64);
++ DEFINED_ON(arm, arm64, x86_shared, mips_shared, loong64, riscv64);
+
+ void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest);
+
+@@ -3764,7 +3772,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ // convention, which requires predictable high bits. In practice, this means
+ // that the 32-bit value will be zero-extended or sign-extended to 64 bits as
+ // appropriate for the platform.
+- void widenInt32(Register r) DEFINED_ON(arm64, x64, mips64, loong64);
++ void widenInt32(Register r) DEFINED_ON(arm64, x64, mips64, loong64, riscv64);
+
+ // As enterFakeExitFrame(), but using register conventions appropriate for
+ // wasm stubs.
+@@ -5006,7 +5014,7 @@ class MacroAssembler : public MacroAssemblerSpecific {
+ inline void addStackPtrTo(T t);
+
+ void subFromStackPtr(Imm32 imm32)
+- DEFINED_ON(mips32, mips64, loong64, arm, x86, x64);
++ DEFINED_ON(mips32, mips64, loong64, arm, x86, x64, riscv64);
+ void subFromStackPtr(Register reg);
+
+ template <typename T>
+diff --git a/js/src/jit/MoveEmitter.h b/js/src/jit/MoveEmitter.h
+index a51cbc100a..ea4d92bedc 100644
+--- a/js/src/jit/MoveEmitter.h
++++ b/js/src/jit/MoveEmitter.h
+@@ -17,6 +17,8 @@
+ # include "jit/mips32/MoveEmitter-mips32.h"
+ #elif defined(JS_CODEGEN_MIPS64)
+ # include "jit/mips64/MoveEmitter-mips64.h"
++#elif defined(JS_CODEGEN_RISCV64)
++# include "jit/riscv64/MoveEmitter-riscv64.h"
+ #elif defined(JS_CODEGEN_LOONG64)
+ # include "jit/loong64/MoveEmitter-loong64.h"
+ #elif defined(JS_CODEGEN_NONE)
+diff --git a/js/src/jit/Registers.h b/js/src/jit/Registers.h
+index 2c1cec0771..baf0630e07 100644
+--- a/js/src/jit/Registers.h
++++ b/js/src/jit/Registers.h
+@@ -20,6 +20,8 @@
+ # include "jit/mips32/Architecture-mips32.h"
+ #elif defined(JS_CODEGEN_MIPS64)
+ # include "jit/mips64/Architecture-mips64.h"
++#elif defined(JS_CODEGEN_RISCV64)
++# include "jit/riscv64/Architecture-riscv64.h"
+ #elif defined(JS_CODEGEN_LOONG64)
+ # include "jit/loong64/Architecture-loong64.h"
+ #elif defined(JS_CODEGEN_NONE)
+diff --git a/js/src/jit/SharedICHelpers-inl.h b/js/src/jit/SharedICHelpers-inl.h
+index 60a77956f0..242f5d3f27 100644
+--- a/js/src/jit/SharedICHelpers-inl.h
++++ b/js/src/jit/SharedICHelpers-inl.h
+@@ -17,6 +17,8 @@
+ # include "jit/arm64/SharedICHelpers-arm64-inl.h"
+ #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
+ # include "jit/mips-shared/SharedICHelpers-mips-shared-inl.h"
++#elif defined(JS_CODEGEN_RISCV64)
++# include "jit/riscv64/SharedICHelpers-riscv64-inl.h"
+ #elif defined(JS_CODEGEN_LOONG64)
+ # include "jit/loong64/SharedICHelpers-loong64-inl.h"
+ #elif defined(JS_CODEGEN_NONE)
+diff --git a/js/src/jit/SharedICHelpers.h b/js/src/jit/SharedICHelpers.h
+index da8378ebae..bfe4a1b672 100644
+--- a/js/src/jit/SharedICHelpers.h
++++ b/js/src/jit/SharedICHelpers.h
+@@ -17,6 +17,8 @@
+ # include "jit/arm64/SharedICHelpers-arm64.h"
+ #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
+ # include "jit/mips-shared/SharedICHelpers-mips-shared.h"
++#elif defined(JS_CODEGEN_RISCV64)
++# include "jit/riscv64/SharedICHelpers-riscv64.h"
+ #elif defined(JS_CODEGEN_LOONG64)
+ # include "jit/loong64/SharedICHelpers-loong64.h"
+ #elif defined(JS_CODEGEN_NONE)
+diff --git a/js/src/jit/SharedICRegisters.h b/js/src/jit/SharedICRegisters.h
+index e29f21c28d..4091d9f595 100644
+--- a/js/src/jit/SharedICRegisters.h
++++ b/js/src/jit/SharedICRegisters.h
+@@ -19,6 +19,8 @@
+ # include "jit/mips32/SharedICRegisters-mips32.h"
+ #elif defined(JS_CODEGEN_MIPS64)
+ # include "jit/mips64/SharedICRegisters-mips64.h"
++#elif defined(JS_CODEGEN_RISCV64)
++# include "jit/riscv64/SharedICRegisters-riscv64.h"
+ #elif defined(JS_CODEGEN_LOONG64)
+ # include "jit/loong64/SharedICRegisters-loong64.h"
+ #elif defined(JS_CODEGEN_NONE)
+diff --git a/js/src/jit/moz.build b/js/src/jit/moz.build
+index 967146e32f..1519351bbb 100644
+--- a/js/src/jit/moz.build
++++ b/js/src/jit/moz.build
+@@ -212,6 +212,13 @@ elif CONFIG["JS_CODEGEN_MIPS32"] or CONFIG["JS_CODEGEN_MIPS64"]:
+ ]
+ if CONFIG["JS_SIMULATOR_MIPS64"]:
+ UNIFIED_SOURCES += ["mips64/Simulator-mips64.cpp"]
++elif CONFIG["JS_CODEGEN_RISCV64"]:
++ UNIFIED_SOURCES += [
++ "riscv64/Assembler-riscv64.cpp",
++ "riscv64/Trampoline-riscv64.cpp",
++ ]
++ if CONFIG["JS_SIMULATOR_RISC64"]:
++ UNIFIED_SOURCES += ["riscv64/Simulator-riscv64.cpp"]
+ elif CONFIG["JS_CODEGEN_LOONG64"]:
+ UNIFIED_SOURCES += [
+ "loong64/Architecture-loong64.cpp",
+@@ -225,7 +232,6 @@ elif CONFIG["JS_CODEGEN_LOONG64"]:
+ if CONFIG["JS_SIMULATOR_LOONG64"]:
+ UNIFIED_SOURCES += ["loong64/Simulator-loong64.cpp"]
+
+-
+ # Generate jit/MIROpsGenerated.h from jit/MIROps.yaml
+ GeneratedFile(
+ "MIROpsGenerated.h",
+diff --git a/js/src/jit/riscv64/Architecture-riscv64.h b/js/src/jit/riscv64/Architecture-riscv64.h
+new file mode 100644
+index 0000000000..a676dc142e
+--- /dev/null
++++ b/js/src/jit/riscv64/Architecture-riscv64.h
+@@ -0,0 +1,404 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
++ * vim: set ts=8 sts=2 et sw=2 tw=80:
++ * This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#ifndef jit_riscv64_Architecture_riscv64_h
++#define jit_riscv64_Architecture_riscv64_h
++
++// JitSpewer.h is included through MacroAssembler implementations for other
++// platforms, so include it here to avoid inadvertent build bustage.
++#include "jit/JitSpewer.h"
++
++#include "jit/shared/Architecture-shared.h"
++
++namespace js {
++namespace jit {
++
++static const uint32_t SimdMemoryAlignment =
++ 4; // Make it 4 to avoid a bunch of div-by-zero warnings
++static const uint32_t WasmStackAlignment = 8;
++static const uint32_t WasmTrapInstructionLength = 0;
++
++// See comments in wasm::GenerateFunctionPrologue.
++static constexpr uint32_t WasmCheckedCallEntryOffset = 0u;
++static constexpr uint32_t WasmCheckedTailEntryOffset = 1u;
++
++class Registers {
++ public:
++ enum RegisterID {
++ x0 = 0,
++ zero = 0,
++ x1 = 1,
++ ra = 1,
++ x2 = 2,
++ sp = 2,
++ x3 = 3,
++ gp = 3,
++ x4 = 4,
++ tp = 4,
++ x5 = 5,
++ t0 = 5,
++ x6 = 6,
++ t1 = 6,
++ x7 = 7,
++ t2 = 7,
++ x8 = 8,
++ fp = 8,
++ s0 = 8,
++ x9 = 9,
++ s1 = 9,
++ x10 = 10,
++ a0 = 10,
++ x11 = 11,
++ a1 = 11,
++ x12 = 12,
++ a2 = 12,
++ x13 = 13,
++ a3 = 13,
++ x14 = 14,
++ a4 = 14,
++ x15 = 15,
++ a5 = 15,
++ x16 = 16,
++ a6 = 16,
++ x17 = 17,
++ a7 = 17,
++ x18 = 18,
++ s2 = 18,
++ x19 = 19,
++ s3 = 19,
++ x20 = 20,
++ s4 = 20,
++ x21 = 21,
++ s5 = 21,
++ x22 = 22,
++ s6 = 22,
++ x23 = 23,
++ s7 = 23,
++ x24 = 24,
++ s8 = 24,
++ x25 = 25,
++ s9 = 25,
++ x26 = 26,
++ s10 = 26,
++ x27 = 27,
++ s11 = 27,
++ x28 = 28,
++ t3 = 28,
++ x29 = 29,
++ t4 = 29,
++ x30 = 30,
++ t5 = 30,
++ x31 = 31,
++ t6 = 31,
++ invalid_reg
++ };
++ typedef uint8_t Code;
++ typedef RegisterID Encoding;
++ union RegisterContent {
++ uintptr_t r;
++ };
++
++ typedef uint32_t SetType;
++
++ static uint32_t SetSize(SetType x) {
++ static_assert(sizeof(SetType) == 4, "SetType must be 32 bits");
++ return mozilla::CountPopulation32(x);
++ }
++ static uint32_t FirstBit(SetType x) {
++ return mozilla::CountTrailingZeroes32(x);
++ }
++ static uint32_t LastBit(SetType x) {
++ return 31 - mozilla::CountLeadingZeroes32(x);
++ }
++
++ static const char* GetName(uint32_t code) {
++ // clang-format off
++ static const char* const Names[] = {
++ "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
++ "fp", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
++ "a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
++ "s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6"};
++ // clang-format on
++ static_assert(Total == sizeof(Names) / sizeof(Names[0]),
++ "Table is the correct size");
++ if (code >= Total) {
++ return "invalid";
++ }
++ return Names[code];
++ }
++
++ static Code FromName(const char* name) {
++ for (size_t i = 0; i < Total; i++) {
++ if (strcmp(GetName(Code(i)), name) == 0) {
++ return Code(i);
++ }
++ }
++ return Invalid;
++ }
++
++ static const Encoding StackPointer = sp;
++ static const Encoding Invalid = invalid_reg;
++ static const uint32_t Total = 32;
++ static const uint32_t TotalPhys = 32;
++ static const uint32_t Allocatable = 28;
++ static const SetType AllMask = 0xffffffff;
++ static const SetType ArgRegMask =
++ (1 << Registers::a0) | (1 << Registers::a1) | (1 << Registers::a2) |
++ (1 << Registers::a3) | (1 << Registers::a4) | (1 << Registers::a5) |
++ (1 << Registers::a6) | (1 << Registers::a7);
++ static const SetType VolatileMask =
++ (1 << Registers::a0) | (1 << Registers::a1) | (1 << Registers::a2) |
++ (1 << Registers::a3) | (1 << Registers::a4) | (1 << Registers::a5) |
++ (1 << Registers::a6) | (1 << Registers::a7) | (1 << Registers::t0) |
++ (1 << Registers::t1) | (1 << Registers::t2) | (1 << Registers::t3) |
++ (1 << Registers::t4) | (1 << Registers::t5) | (1 << Registers::t6);
++ static const SetType NonVolatileMask =
++ (1 << Registers::s0) | (1 << Registers::s1) | (1 << Registers::s2) |
++ (1 << Registers::s3) | (1 << Registers::s4) | (1 << Registers::s5) |
++ (1 << Registers::s6) | (1 << Registers::s7) | (1 << Registers::s8) |
++ (1 << Registers::s9) | (1 << Registers::s10) | (1 << Registers::s11);
++ static const SetType NonAllocatableMask =
++ (1 << Registers::zero) | (1 << Registers::sp) | (1 << Registers::tp) |
++ (1 << Registers::gp);
++ static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
++ static const SetType JSCallMask = 0;
++ static const SetType CallMask = 0;
++};
++
++typedef uint8_t PackedRegisterMask;
++
++class FloatRegisters {
++ public:
++ enum FPRegisterID {
++ f0 = 0,
++ ft0 = 0,
++ f1 = 1,
++ ft1 = 1,
++ f2 = 2,
++ ft2 = 2,
++ f3 = 3,
++ ft3 = 3,
++ f4 = 4,
++ ft4 = 4,
++ f5 = 5,
++ ft5 = 5,
++ f6 = 6,
++ ft6 = 6,
++ f7 = 7,
++ ft7 = 7,
++ f8 = 8,
++ fs0 = 8,
++ f9 = 9,
++ fs1 = 9,
++ f10 = 10,
++ fa0 = 10,
++ f11 = 11,
++ fa1 = 11,
++ f12 = 12,
++ fa2 = 12,
++ f13 = 13,
++ fa3 = 13,
++ f14 = 14,
++ fa4 = 14,
++ f15 = 15,
++ fa5 = 15,
++ f16 = 16,
++ fa6 = 16,
++ f17 = 17,
++ fa7 = 17,
++ f18 = 18,
++ fs2 = 18,
++ f19 = 19,
++ fs3 = 19,
++ f20 = 20,
++ fs4 = 20,
++ f21 = 21,
++ fs5 = 21,
++ f22 = 22,
++ fs6 = 22,
++ f23 = 23,
++ fs7 = 23,
++ f24 = 24,
++ fs8 = 24,
++ f25 = 25,
++ fs9 = 25,
++ f26 = 26,
++ fs10 = 26,
++ f27 = 27,
++ fs11 = 27,
++ f28 = 28,
++ ft8 = 28,
++ f29 = 29,
++ ft9 = 29,
++ f30 = 30,
++ ft10 = 30,
++ f31 = 31,
++ ft11 = 31,
++ invalid_reg
++ };
++
++ typedef uint8_t Code;
++ typedef FPRegisterID Encoding;
++ typedef uint32_t SetType;
++
++ enum Kind : uint8_t { Double, Single };
++
++ union RegisterContent {
++ float s;
++ double d;
++ };
++
++ static const char* GetName(uint32_t code) {
++ // clang-format off
++ static const char* const Names[] = {
++ "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7",
++ "fs0", "fs1", "fa0", "fa1", "fa2", "fa3", "fa4", "fa5",
++ "fa6", "fa7", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
++ "fs8", "fs9", "fs10", "fs11", "ft8", "ft9", "ft10", "ft11",
++ };
++ // clang-format on
++ static_assert(Total == sizeof(Names) / sizeof(Names[0]),
++ "Table is the correct size");
++ if (code >= Total) {
++ return "invalid";
++ }
++ return Names[code];
++ }
++ static Code FromName(const char* name) {
++ for (size_t i = 0; i < Total; i++) {
++ if (strcmp(GetName(i), name) == 0) {
++ return Code(i);
++ }
++ }
++
++ return Invalid;
++ }
++
++ static constexpr Encoding encoding(Code c) { return Encoding(c & 31); }
++
++ static const Encoding Invalid = invalid_reg;
++ static const uint32_t Total = 32;
++ static const uint32_t TotalPhys = 32;
++ static const uint32_t Allocatable = 32;
++ static const SetType AllMask = 0xffffffff;
++ static const SetType AllDoubleMask = 0;
++ static const SetType AllSingleMask = 0;
++ static const SetType VolatileMask =
++ (1 << FloatRegisters::ft0) | (1 << FloatRegisters::ft1) |
++ (1 << FloatRegisters::ft2) | (1 << FloatRegisters::ft3) |
++ (1 << FloatRegisters::ft4) | (1 << FloatRegisters::ft5) |
++ (1 << FloatRegisters::ft6) | (1 << FloatRegisters::ft7) |
++ (1 << FloatRegisters::ft8) | (1 << FloatRegisters::ft9) |
++ (1 << FloatRegisters::ft10) | (1 << FloatRegisters::ft11) |
++ (1 << FloatRegisters::fa0) | (1 << FloatRegisters::fa1) |
++ (1 << FloatRegisters::fa2) | (1 << FloatRegisters::fa3) |
++ (1 << FloatRegisters::fa4) | (1 << FloatRegisters::fa5) |
++ (1 << FloatRegisters::fa6) | (1 << FloatRegisters::fa7);
++ static const SetType NonVolatileMask =
++ (1 << FloatRegisters::fs0) | (1 << FloatRegisters::fs1) |
++ (1 << FloatRegisters::fs2) | (1 << FloatRegisters::fs3) |
++ (1 << FloatRegisters::fs4) | (1 << FloatRegisters::fs5) |
++ (1 << FloatRegisters::fs6) | (1 << FloatRegisters::fs7) |
++ (1 << FloatRegisters::fs8) | (1 << FloatRegisters::fs9) |
++ (1 << FloatRegisters::fs10) | (1 << FloatRegisters::fs11);
++ static const SetType NonAllocatableMask = 0;
++ static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
++};
++
++template <typename T>
++class TypedRegisterSet;
++
++struct FloatRegister {
++ typedef FloatRegisters Codes;
++ typedef size_t Code;
++ typedef Codes::Encoding Encoding;
++ typedef Codes::SetType SetType;
++ typedef Codes::Kind Kind;
++
++ private:
++ uint8_t encoding_;
++ uint8_t kind_;
++ bool invalid_;
++
++ public:
++ constexpr FloatRegister(Encoding encoding)
++ : encoding_(encoding), kind_(FloatRegisters::Double), invalid_(false) {}
++ constexpr FloatRegister(Encoding encoding, Kind kind)
++ : encoding_(encoding), kind_(kind), invalid_(false) {}
++ constexpr FloatRegister()
++ : encoding_(0), kind_(FloatRegisters::Double), invalid_(true) {}
++
++ static uint32_t FirstBit(SetType) { MOZ_CRASH(); }
++ static uint32_t LastBit(SetType) { MOZ_CRASH(); }
++ static FloatRegister FromCode(uint32_t i) {
++ return FloatRegister(FloatRegisters::encoding(i), FloatRegisters::Double);
++ }
++ bool isSingle() const { return kind_ == FloatRegisters::Single; }
++ bool isDouble() const { return kind_ == FloatRegisters::Double; }
++ bool isSimd128() const { return false; }
++ bool isInvalid() const { return invalid_; }
++ FloatRegister asSingle() const { MOZ_CRASH(); }
++ FloatRegister asDouble() const { MOZ_CRASH(); }
++ FloatRegister asSimd128() const { MOZ_CRASH(); }
++ Code code() const { MOZ_CRASH(); }
++ Encoding encoding() const { return Encoding(encoding_); }
++ const char* name() const { return FloatRegisters::GetName(code()); }
++ bool volatile_() const { MOZ_CRASH(); }
++ bool operator!=(FloatRegister) const { MOZ_CRASH(); }
++ bool operator==(FloatRegister) const { MOZ_CRASH(); }
++ bool aliases(FloatRegister) const { MOZ_CRASH(); }
++ uint32_t numAliased() const { MOZ_CRASH(); }
++ FloatRegister aliased(uint32_t) { MOZ_CRASH(); }
++ bool equiv(FloatRegister) const { MOZ_CRASH(); }
++ uint32_t size() const { MOZ_CRASH(); }
++ uint32_t numAlignedAliased() const { MOZ_CRASH(); }
++ FloatRegister alignedAliased(uint32_t) { MOZ_CRASH(); }
++ SetType alignedOrDominatedAliasedSet() const { MOZ_CRASH(); }
++
++ static constexpr RegTypeName DefaultType = RegTypeName::Float64;
++
++ template <RegTypeName = DefaultType>
++ static SetType LiveAsIndexableSet(SetType s) {
++ return SetType(0);
++ }
++
++ template <RegTypeName Name = DefaultType>
++ static SetType AllocatableAsIndexableSet(SetType s) {
++ static_assert(Name != RegTypeName::Any, "Allocatable set are not iterable");
++ return SetType(0);
++ }
++
++ template <typename T>
++ static T ReduceSetForPush(T) {
++ MOZ_CRASH();
++ }
++ uint32_t getRegisterDumpOffsetInBytes() {
++ MOZ_CRASH();
++ return 0;
++ }
++ static uint32_t SetSize(SetType x) {
++ MOZ_CRASH();
++ return 0;
++ }
++ static Code FromName(const char* name) { return 0; }
++
++ // This is used in static initializers, so produce a bogus value instead of
++ // crashing.
++ static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister>&) {
++ return 0;
++ }
++};
++
++inline bool hasUnaliasedDouble() { MOZ_CRASH(); }
++inline bool hasMultiAlias() { MOZ_CRASH(); }
++
++static const uint32_t ShadowStackSpace = 0;
++static const uint32_t JumpImmediateRange = INT32_MAX;
++
++} // namespace jit
++} // namespace js
++
++#endif /* jit_riscv64_Architecture_riscv64_h */
+diff --git a/js/src/jit/riscv64/Assembler-riscv64.cpp b/js/src/jit/riscv64/Assembler-riscv64.cpp
+new file mode 100644
+index 0000000000..90fa6d87a8
+--- /dev/null
++++ b/js/src/jit/riscv64/Assembler-riscv64.cpp
+@@ -0,0 +1,47 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
++ * vim: set ts=8 sts=2 et sw=2 tw=80:
++ * This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#include "jit/riscv64/Assembler-riscv64.h"
++
++using namespace js;
++using namespace js::jit;
++
++ABIArg ABIArgGenerator::next(MIRType type) {
++ switch (type) {
++ case MIRType::Int32:
++ case MIRType::Int64:
++ case MIRType::Pointer:
++ case MIRType::RefOrNull:
++ case MIRType::StackResults:
++ if (intRegIndex_ == NumIntArgRegs) {
++ current_ = ABIArg(stackOffset_);
++ stackOffset_ += sizeof(uintptr_t);
++ break;
++ }
++ current_ = ABIArg(Register::FromCode(intRegIndex_));
++ intRegIndex_++;
++ break;
++
++ case MIRType::Float32:
++ case MIRType::Double:
++ if (floatRegIndex_ == NumFloatArgRegs) {
++ current_ = ABIArg(stackOffset_);
++ stackOffset_ += sizeof(double);
++ break;
++ }
++ current_ = ABIArg(FloatRegister(FloatRegisters::Encoding(floatRegIndex_),
++ type == MIRType::Double
++ ? FloatRegisters::Double
++ : FloatRegisters::Single));
++ floatRegIndex_++;
++ break;
++
++ case MIRType::Simd128:
++ default:
++ MOZ_CRASH("Unexpected argument type");
++ }
++ return current_;
++}
+diff --git a/js/src/jit/riscv64/Assembler-riscv64.h b/js/src/jit/riscv64/Assembler-riscv64.h
+new file mode 100644
+index 0000000000..a58e6c4aff
+--- /dev/null
++++ b/js/src/jit/riscv64/Assembler-riscv64.h
+@@ -0,0 +1,303 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
++ * vim: set ts=8 sts=2 et sw=2 tw=80:
++ * This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#ifndef jit_riscv64_Assembler_riscv64_h
++#define jit_riscv64_Assembler_riscv64_h
++
++#include "mozilla/Sprintf.h"
++#include <iterator>
++
++#include "jit/CompactBuffer.h"
++#include "jit/JitCode.h"
++#include "jit/JitSpewer.h"
++#include "jit/riscv64/Architecture-riscv64.h"
++#include "jit/shared/Assembler-shared.h"
++#include "jit/shared/Disassembler-shared.h"
++#include "jit/shared/IonAssemblerBuffer.h"
++#include "wasm/WasmTypeDecls.h"
++
++namespace js {
++namespace jit {
++
++class MacroAssembler;
++
++static constexpr Register t0{Registers::t0};
++static constexpr Register t1{Registers::t1};
++static constexpr Register t2{Registers::t2};
++static constexpr Register t3{Registers::t3};
++static constexpr Register t4{Registers::t4};
++static constexpr Register t5{Registers::t5};
++static constexpr Register t6{Registers::t6};
++static constexpr Register s0{Registers::s0};
++static constexpr Register s4{Registers::s4};
++
++static constexpr Register StackPointer{Registers::sp};
++static constexpr Register FramePointer{Registers::fp};
++static constexpr Register ReturnReg{Registers::a0};
++static constexpr FloatRegister InvalidFloatReg;
++static constexpr FloatRegister ReturnFloat32Reg{FloatRegisters::fa0,
++ FloatRegisters::Single};
++static constexpr FloatRegister ReturnDoubleReg{FloatRegisters::fa0,
++ FloatRegisters::Double};
++static constexpr FloatRegister ReturnSimd128Reg = InvalidFloatReg;
++static constexpr FloatRegister ScratchSimd128Reg = InvalidFloatReg;
++static constexpr FloatRegister ScratchFloat32Reg_ = InvalidFloatReg;
++static constexpr FloatRegister ScratchDoubleReg_ = InvalidFloatReg;
++
++static constexpr Register ScratchRegister = t6;
++
++// Helper class for ScratchRegister usage. Asserts that only one piece
++// of code thinks it has exclusive ownership of the scratch register.
++struct ScratchRegisterScope : public AutoRegisterScope {
++ explicit ScratchRegisterScope(MacroAssembler& masm)
++ : AutoRegisterScope(masm, ScratchRegister) {}
++};
++
++struct SecondScratchRegisterScope : public AutoRegisterScope {
++ explicit SecondScratchRegisterScope(MacroAssembler& masm);
++};
++
++struct ScratchFloat32Scope : AutoFloatRegisterScope {
++ explicit ScratchFloat32Scope(MacroAssembler& masm)
++ : AutoFloatRegisterScope(masm, ScratchFloat32Reg_) {}
++};
++
++struct ScratchDoubleScope : AutoFloatRegisterScope {
++ explicit ScratchDoubleScope(MacroAssembler& masm)
++ : AutoFloatRegisterScope(masm, ScratchDoubleReg_) {}
++};
++
++static constexpr Register OsrFrameReg{Registers::invalid_reg};
++static constexpr Register PreBarrierReg{Registers::invalid_reg};
++static constexpr Register InterpreterPCReg{Registers::invalid_reg};
++static constexpr Register CallTempReg0 = t0;
++static constexpr Register CallTempReg1 = t1;
++static constexpr Register CallTempReg2 = t2;
++static constexpr Register CallTempReg3 = t3;
++static constexpr Register CallTempReg4 = t4;
++static constexpr Register CallTempReg5 = t5;
++static constexpr Register InvalidReg{Registers::invalid_reg};
++static constexpr Register CallTempNonArgRegs[] = {t0, t1, t2, t3, t4, t5, t6};
++static const uint32_t NumCallTempNonArgRegs = std::size(CallTempNonArgRegs);
++
++static constexpr Register IntArgReg0{Registers::a0};
++static constexpr Register IntArgReg1{Registers::a1};
++static constexpr Register IntArgReg2{Registers::a2};
++static constexpr Register IntArgReg3{Registers::a3};
++static constexpr Register IntArgReg4{Registers::a4};
++static constexpr Register IntArgReg5{Registers::a5};
++static constexpr Register IntArgReg6{Registers::a6};
++static constexpr Register IntArgReg7{Registers::a7};
++static constexpr Register HeapReg{Registers::invalid_reg};
++
++// Registerd used in RegExpTester instruction (do not use ReturnReg).
++static constexpr Register RegExpTesterRegExpReg = CallTempReg0;
++static constexpr Register RegExpTesterStringReg = CallTempReg1;
++static constexpr Register RegExpTesterLastIndexReg = CallTempReg2;
++
++// Registerd used in RegExpMatcher instruction (do not use JSReturnOperand).
++static constexpr Register RegExpMatcherRegExpReg = CallTempReg0;
++static constexpr Register RegExpMatcherStringReg = CallTempReg1;
++static constexpr Register RegExpMatcherLastIndexReg = CallTempReg2;
++
++static constexpr Register JSReturnReg_Type{Registers::a3};
++static constexpr Register JSReturnReg_Data{Registers::a2};
++static constexpr Register JSReturnReg{Registers::a2};
++
++static constexpr Register64 ReturnReg64(ReturnReg);
++
++static constexpr Register ABINonArgReg0{Registers::s0};
++static constexpr Register ABINonArgReg1{Registers::s1};
++static constexpr Register ABINonArgReg2{Registers::s2};
++static constexpr Register ABINonArgReg3{Registers::s3};
++static constexpr Register ABINonArgReturnReg0{Registers::s0};
++static constexpr Register ABINonArgReturnReg1{Registers::s1};
++static constexpr Register ABINonVolatileReg{Registers::fp};
++static constexpr Register ABINonArgReturnVolatileReg{Registers::ra};
++
++static constexpr FloatRegister ABINonArgDoubleReg = InvalidFloatReg;
++
++// Instance pointer argument register for WebAssembly functions. This must not
++// alias any other register used for passing function arguments or return
++// values. Preserved by WebAssembly functions.
++static constexpr Register InstanceReg = s4;
++
++static constexpr Register WasmTableCallScratchReg0{Registers::invalid_reg};
++static constexpr Register WasmTableCallScratchReg1{Registers::invalid_reg};
++static constexpr Register WasmTableCallSigReg{Registers::invalid_reg};
++static constexpr Register WasmTableCallIndexReg{Registers::invalid_reg};
++static constexpr Register WasmTlsReg{Registers::invalid_reg};
++static constexpr Register WasmJitEntryReturnScratch{Registers::invalid_reg};
++
++static constexpr uint32_t ABIStackAlignment = 16;
++static constexpr uint32_t CodeAlignment = 16;
++static constexpr uint32_t JitStackAlignment = 8;
++static constexpr uint32_t JitStackValueAlignment =
++ JitStackAlignment / sizeof(Value);
++
++static const Scale ScalePointer = TimesOne;
++
++class Instruction;
++typedef js::jit::AssemblerBuffer<1024, Instruction> RISCVBuffer;
++
++class Assembler : public AssemblerShared {
++ public:
++ enum RISCVCondition : uint32_t {
++ EQ = 0b000,
++ NE = 0b001,
++ LT = 0b100,
++ GE = 0b101,
++ LTU = 0b110,
++ GEU = 0b111,
++ };
++
++ enum Condition {
++ Equal,
++ NotEqual,
++ Above,
++ AboveOrEqual,
++ Below,
++ BelowOrEqual,
++ GreaterThan,
++ GreaterThanOrEqual,
++ LessThan,
++ LessThanOrEqual,
++ Overflow,
++ CarrySet,
++ CarryClear,
++ Signed,
++ NotSigned,
++ Zero,
++ NonZero,
++ Always,
++ };
++
++ enum DoubleCondition {
++ DoubleOrdered,
++ DoubleEqual,
++ DoubleNotEqual,
++ DoubleGreaterThan,
++ DoubleGreaterThanOrEqual,
++ DoubleLessThan,
++ DoubleLessThanOrEqual,
++ DoubleUnordered,
++ DoubleEqualOrUnordered,
++ DoubleNotEqualOrUnordered,
++ DoubleGreaterThanOrUnordered,
++ DoubleGreaterThanOrEqualOrUnordered,
++ DoubleLessThanOrUnordered,
++ DoubleLessThanOrEqualOrUnordered
++ };
++
++ RISCVBuffer m_buffer;
++
++ BufferOffset nextOffset() { return m_buffer.nextOffset(); }
++
++ static Condition InvertCondition(Condition) { MOZ_CRASH(); }
++
++ static DoubleCondition InvertCondition(DoubleCondition) { MOZ_CRASH(); }
++
++ static void TraceJumpRelocations(JSTracer* trc, JitCode* code,
++ CompactBufferReader& reader);
++ static void TraceDataRelocations(JSTracer* trc, JitCode* code,
++ CompactBufferReader& reader);
++
++ template <typename T, typename S>
++ static void PatchDataWithValueCheck(CodeLocationLabel, T, S) {
++ MOZ_CRASH();
++ }
++ static void PatchWrite_Imm32(CodeLocationLabel, Imm32) { MOZ_CRASH(); }
++
++ static void PatchWrite_NearCall(CodeLocationLabel, CodeLocationLabel) {
++ MOZ_CRASH();
++ }
++ static uint32_t PatchWrite_NearCallSize() { MOZ_CRASH(); }
++
++ static void ToggleToJmp(CodeLocationLabel) { MOZ_CRASH(); }
++ static void ToggleToCmp(CodeLocationLabel) { MOZ_CRASH(); }
++ static void ToggleCall(CodeLocationLabel, bool) { MOZ_CRASH(); }
++
++ static void Bind(uint8_t* rawCode, const CodeLabel& label) { MOZ_CRASH(); }
++
++ static uintptr_t GetPointer(uint8_t*) { MOZ_CRASH(); }
++
++ static bool HasRoundInstruction(RoundingMode) { return false; }
++
++ void verifyHeapAccessDisassembly(uint32_t begin, uint32_t end,
++ const Disassembler::HeapAccess& heapAccess) {
++ MOZ_CRASH();
++ }
++
++ void setUnlimitedBuffer() { MOZ_CRASH(); }
++
++ MOZ_ALWAYS_INLINE BufferOffset writeInst(uint32_t x) {
++ MOZ_ASSERT(hasCreator());
++ return m_buffer.putInt(x);
++ }
++};
++
++class Instruction {
++ protected:
++ uint32_t data;
++
++ // Standard constructor
++ Instruction(uint32_t data_) : data(data_) {}
++
++ public:
++ uint32_t encode() const { return data; }
++
++ void setData(uint32_t data) { this->data = data; }
++ Instruction* next();
++ const uint32_t* raw() const { return &data; }
++ uint32_t size() const { return sizeof(data); }
++};
++
++class Operand {
++ public:
++ enum Kind { REG };
++
++ private:
++ Kind kind_ : 4;
++ uint32_t reg_ : 5;
++ int32_t offset_;
++
++ public:
++ explicit Operand(const Register reg)
++ : kind_(REG), reg_(reg.code()), offset_(0) {}
++ explicit Operand(const FloatRegister) { MOZ_CRASH(); }
++ explicit Operand(const Address& adress) { MOZ_CRASH(); }
++ explicit Operand(Register reg, Imm32 offset)
++ : kind_(REG), reg_(reg.code()), offset_(offset.value) {}
++ explicit Operand(Register reg, int32_t offset)
++ : kind_(REG), reg_(reg.code()), offset_(offset) {}
++
++ Kind kind() const { return kind_; }
++};
++
++static const uint32_t NumIntArgRegs = 8;
++static const uint32_t NumFloatArgRegs = 8;
++
++class ABIArgGenerator {
++ public:
++ ABIArgGenerator()
++ : intRegIndex_(0), floatRegIndex_(0), stackOffset_(0), current_() {}
++
++ ABIArg next(MIRType);
++ ABIArg& current() { return current_; }
++ uint32_t stackBytesConsumedSoFar() const { return stackOffset_; }
++ void increaseStackOffset(uint32_t bytes) { stackOffset_ += bytes; }
++
++ private:
++ unsigned intRegIndex_;
++ unsigned floatRegIndex_;
++ uint32_t stackOffset_;
++ ABIArg current_;
++};
++
++} // namespace jit
++} // namespace js
++
++#endif /* jit_riscv64_Assembler_riscv64_h */
+diff --git a/js/src/jit/riscv64/CodeGenerator-riscv64.h b/js/src/jit/riscv64/CodeGenerator-riscv64.h
+new file mode 100644
+index 0000000000..db30b32283
+--- /dev/null
++++ b/js/src/jit/riscv64/CodeGenerator-riscv64.h
+@@ -0,0 +1,78 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
++ * vim: set ts=8 sts=2 et sw=2 tw=80:
++ * This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#ifndef jit_riscv64_CodeGenerator_riscv64_h
++#define jit_riscv64_CodeGenerator_riscv64_h
++
++#include "jit/shared/CodeGenerator-shared.h"
++
++namespace js {
++namespace jit {
++
++class CodeGeneratorRiscv64 : public CodeGeneratorShared {
++ protected:
++ CodeGeneratorRiscv64(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm)
++ : CodeGeneratorShared(gen, graph, masm) {
++ MOZ_CRASH();
++ }
++
++ MoveOperand toMoveOperand(LAllocation) const { MOZ_CRASH(); }
++ template <typename T1, typename T2>
++ void bailoutCmp32(Assembler::Condition, T1, T2, LSnapshot*) {
++ MOZ_CRASH();
++ }
++ template <typename T1, typename T2>
++ void bailoutTest32(Assembler::Condition, T1, T2, LSnapshot*) {
++ MOZ_CRASH();
++ }
++ template <typename T1, typename T2>
++ void bailoutCmpPtr(Assembler::Condition, T1, T2, LSnapshot*) {
++ MOZ_CRASH();
++ }
++ void bailoutTestPtr(Assembler::Condition, Register, Register, LSnapshot*) {
++ MOZ_CRASH();
++ }
++ void bailoutIfFalseBool(Register, LSnapshot*) { MOZ_CRASH(); }
++ void bailoutFrom(Label*, LSnapshot*) { MOZ_CRASH(); }
++ void bailout(LSnapshot*) { MOZ_CRASH(); }
++ void bailoutIf(Assembler::Condition, LSnapshot*) { MOZ_CRASH(); }
++ bool generateOutOfLineCode() { MOZ_CRASH(); }
++ void testNullEmitBranch(Assembler::Condition, ValueOperand, MBasicBlock*,
++ MBasicBlock*) {
++ MOZ_CRASH();
++ }
++ void testUndefinedEmitBranch(Assembler::Condition, ValueOperand, MBasicBlock*,
++ MBasicBlock*) {
++ MOZ_CRASH();
++ }
++ void testObjectEmitBranch(Assembler::Condition, ValueOperand, MBasicBlock*,
++ MBasicBlock*) {
++ MOZ_CRASH();
++ }
++ void testZeroEmitBranch(Assembler::Condition, Register, MBasicBlock*,
++ MBasicBlock*) {
++ MOZ_CRASH();
++ }
++ void emitTableSwitchDispatch(MTableSwitch*, Register, Register) {
++ MOZ_CRASH();
++ }
++ void emitBigIntDiv(LBigIntDiv*, Register, Register, Register, Label*) {
++ MOZ_CRASH();
++ }
++ void emitBigIntMod(LBigIntMod*, Register, Register, Register, Label*) {
++ MOZ_CRASH();
++ }
++ ValueOperand ToValue(LInstruction*, size_t) { MOZ_CRASH(); }
++ ValueOperand ToTempValue(LInstruction*, size_t) { MOZ_CRASH(); }
++ void generateInvalidateEpilogue() { MOZ_CRASH(); }
++};
++
++typedef CodeGeneratorRiscv64 CodeGeneratorSpecific;
++
++} // namespace jit
++} // namespace js
++
++#endif /* jit_riscv64_CodeGenerator_riscv64_h */
+diff --git a/js/src/jit/riscv64/LIR-riscv64.h b/js/src/jit/riscv64/LIR-riscv64.h
+new file mode 100644
+index 0000000000..59d42c6c75
+--- /dev/null
++++ b/js/src/jit/riscv64/LIR-riscv64.h
+@@ -0,0 +1,111 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
++ * vim: set ts=8 sts=2 et sw=2 tw=80:
++ * This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#ifndef jit_riscv64_LIR_riscv64_h
++#define jit_riscv64_LIR_riscv64_h
++
++namespace js {
++namespace jit {
++
++class LUnboxFloatingPoint : public LInstruction {
++ public:
++ LIR_HEADER(UnboxFloatingPoint)
++ static const size_t Input = 0;
++
++ MUnbox* mir() const { MOZ_CRASH(); }
++
++ const LDefinition* output() const { MOZ_CRASH(); }
++ MIRType type() const { MOZ_CRASH(); }
++};
++
++class LTableSwitch : public LInstruction {
++ public:
++ LIR_HEADER(TableSwitch)
++ MTableSwitch* mir() { MOZ_CRASH(); }
++
++ const LAllocation* index() { MOZ_CRASH(); }
++ const LDefinition* tempInt() { MOZ_CRASH(); }
++ const LDefinition* tempPointer() { MOZ_CRASH(); }
++};
++
++class LTableSwitchV : public LInstruction {
++ public:
++ LIR_HEADER(TableSwitchV)
++ MTableSwitch* mir() { MOZ_CRASH(); }
++
++ const LDefinition* tempInt() { MOZ_CRASH(); }
++ const LDefinition* tempFloat() { MOZ_CRASH(); }
++ const LDefinition* tempPointer() { MOZ_CRASH(); }
++
++ static const size_t InputValue = 0;
++};
++
++class LWasmUint32ToFloat32 : public LInstructionHelper<1, 1, 0> {
++ public:
++ explicit LWasmUint32ToFloat32(const LAllocation&)
++ : LInstructionHelper(Opcode::Invalid) {
++ MOZ_CRASH();
++ }
++};
++
++class LUnbox : public LInstructionHelper<1, 2, 0> {
++ public:
++ MUnbox* mir() const { MOZ_CRASH(); }
++ const LAllocation* payload() { MOZ_CRASH(); }
++ const LAllocation* type() { MOZ_CRASH(); }
++ const char* extraName() const { MOZ_CRASH(); }
++};
++class LDivI : public LBinaryMath<1> {
++ public:
++ LDivI(const LAllocation&, const LAllocation&, const LDefinition&)
++ : LBinaryMath(Opcode::Invalid) {
++ MOZ_CRASH();
++ }
++ MDiv* mir() const { MOZ_CRASH(); }
++};
++class LDivPowTwoI : public LInstructionHelper<1, 1, 0> {
++ public:
++ LDivPowTwoI(const LAllocation&, int32_t)
++ : LInstructionHelper(Opcode::Invalid) {
++ MOZ_CRASH();
++ }
++ const LAllocation* numerator() { MOZ_CRASH(); }
++ int32_t shift() { MOZ_CRASH(); }
++ MDiv* mir() const { MOZ_CRASH(); }
++};
++class LModI : public LBinaryMath<1> {
++ public:
++ LModI(const LAllocation&, const LAllocation&, const LDefinition&)
++ : LBinaryMath(Opcode::Invalid) {
++ MOZ_CRASH();
++ }
++
++ const LDefinition* callTemp() { MOZ_CRASH(); }
++ MMod* mir() const { MOZ_CRASH(); }
++};
++class LWasmUint32ToDouble : public LInstructionHelper<1, 1, 0> {
++ public:
++ explicit LWasmUint32ToDouble(const LAllocation&)
++ : LInstructionHelper(Opcode::Invalid) {
++ MOZ_CRASH();
++ }
++};
++class LModPowTwoI : public LInstructionHelper<1, 1, 0> {
++ public:
++ int32_t shift() { MOZ_CRASH(); }
++ LModPowTwoI(const LAllocation& lhs, int32_t shift)
++ : LInstructionHelper(Opcode::Invalid) {
++ MOZ_CRASH();
++ }
++ MMod* mir() const { MOZ_CRASH(); }
++};
++
++class LMulI : public LInstruction {};
++
++} // namespace jit
++} // namespace js
++
++#endif /* jit_riscv64_LIR_riscv64_h */
+diff --git a/js/src/jit/riscv64/Lowering-riscv64.h b/js/src/jit/riscv64/Lowering-riscv64.h
+new file mode 100644
+index 0000000000..a68e52b872
+--- /dev/null
++++ b/js/src/jit/riscv64/Lowering-riscv64.h
+@@ -0,0 +1,130 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
++ * vim: set ts=8 sts=2 et sw=2 tw=80:
++ * This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#ifndef jit_riscv64_Lowering_riscv64_h
++#define jit_riscv64_Lowering_riscv64_h
++
++#include "jit/shared/Lowering-shared.h"
++
++namespace js {
++namespace jit {
++
++class LIRGeneratorRiscv64 : public LIRGeneratorShared {
++ protected:
++ LIRGeneratorRiscv64(MIRGenerator* gen, MIRGraph& graph, LIRGraph& lirGraph)
++ : LIRGeneratorShared(gen, graph, lirGraph) {
++ MOZ_CRASH();
++ }
++
++ LBoxAllocation useBoxFixed(MDefinition*, Register, Register,
++ bool useAtStart = false) {
++ MOZ_CRASH();
++ }
++
++ LAllocation useByteOpRegister(MDefinition*) { MOZ_CRASH(); }
++ LAllocation useByteOpRegisterAtStart(MDefinition*) { MOZ_CRASH(); }
++ LAllocation useByteOpRegisterOrNonDoubleConstant(MDefinition*) {
++ MOZ_CRASH();
++ }
++ LDefinition tempByteOpRegister() { MOZ_CRASH(); }
++ LDefinition tempToUnbox() { MOZ_CRASH(); }
++ bool needTempForPostBarrier() { MOZ_CRASH(); }
++ void lowerUntypedPhiInput(MPhi*, uint32_t, LBlock*, size_t) { MOZ_CRASH(); }
++ void lowerInt64PhiInput(MPhi*, uint32_t, LBlock*, size_t) { MOZ_CRASH(); }
++ void defineInt64Phi(MPhi*, size_t) { MOZ_CRASH(); }
++ void lowerForShift(LInstructionHelper<1, 2, 0>*, MDefinition*, MDefinition*,
++ MDefinition*) {
++ MOZ_CRASH();
++ }
++ void lowerUrshD(MUrsh*) { MOZ_CRASH(); }
++ void lowerPowOfTwoI(MPow*) { MOZ_CRASH(); }
++ template <typename T>
++ void lowerForALU(T, MDefinition*, MDefinition*, MDefinition* v = nullptr) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void lowerForFPU(T, MDefinition*, MDefinition*, MDefinition* v = nullptr) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void lowerForALUInt64(T, MDefinition*, MDefinition*,
++ MDefinition* v = nullptr) {
++ MOZ_CRASH();
++ }
++ void lowerForMulInt64(LMulI64*, MMul*, MDefinition*,
++ MDefinition* v = nullptr) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void lowerForShiftInt64(T, MDefinition*, MDefinition*,
++ MDefinition* v = nullptr) {
++ MOZ_CRASH();
++ }
++ void lowerForBitAndAndBranch(LBitAndAndBranch*, MInstruction*, MDefinition*,
++ MDefinition*) {
++ MOZ_CRASH();
++ }
++ void lowerForCompareI64AndBranch(MTest*, MCompare*, JSOp, MDefinition*,
++ MDefinition*, MBasicBlock*, MBasicBlock*) {
++ MOZ_CRASH();
++ }
++
++ void lowerConstantDouble(double, MInstruction*) { MOZ_CRASH(); }
++ void lowerConstantFloat32(float, MInstruction*) { MOZ_CRASH(); }
++ void lowerTruncateDToInt32(MTruncateToInt32*) { MOZ_CRASH(); }
++ void lowerTruncateFToInt32(MTruncateToInt32*) { MOZ_CRASH(); }
++ void lowerBuiltinInt64ToFloatingPoint(MBuiltinInt64ToFloatingPoint* ins) {
++ MOZ_CRASH();
++ }
++ void lowerWasmBuiltinTruncateToInt64(MWasmBuiltinTruncateToInt64* ins) {
++ MOZ_CRASH();
++ }
++ void lowerWasmBuiltinTruncateToInt32(MWasmBuiltinTruncateToInt32* ins) {
++ MOZ_CRASH();
++ }
++ void lowerDivI(MDiv*) { MOZ_CRASH(); }
++ void lowerModI(MMod*) { MOZ_CRASH(); }
++ void lowerDivI64(MDiv*) { MOZ_CRASH(); }
++ void lowerWasmBuiltinDivI64(MWasmBuiltinDivI64* div) { MOZ_CRASH(); }
++ void lowerModI64(MMod*) { MOZ_CRASH(); }
++ void lowerWasmBuiltinModI64(MWasmBuiltinModI64* mod) { MOZ_CRASH(); }
++ void lowerNegI(MInstruction*, MDefinition*) { MOZ_CRASH(); }
++ void lowerNegI64(MInstruction*, MDefinition*) { MOZ_CRASH(); }
++ void lowerMulI(MMul*, MDefinition*, MDefinition*) { MOZ_CRASH(); }
++ void lowerUDiv(MDiv*) { MOZ_CRASH(); }
++ void lowerUMod(MMod*) { MOZ_CRASH(); }
++ void lowerWasmSelectI(MWasmSelect* select) { MOZ_CRASH(); }
++ void lowerWasmSelectI64(MWasmSelect* select) { MOZ_CRASH(); }
++ void lowerWasmCompareAndSelect(MWasmSelect* ins, MDefinition* lhs,
++ MDefinition* rhs, MCompare::CompareType compTy,
++ JSOp jsop) {
++ MOZ_CRASH();
++ }
++ bool canSpecializeWasmCompareAndSelect(MCompare::CompareType compTy,
++ MIRType insTy) {
++ MOZ_CRASH();
++ }
++
++ void lowerBigIntLsh(MBigIntLsh*) { MOZ_CRASH(); }
++ void lowerBigIntRsh(MBigIntRsh*) { MOZ_CRASH(); }
++ void lowerBigIntDiv(MBigIntDiv*) { MOZ_CRASH(); }
++ void lowerBigIntMod(MBigIntMod*) { MOZ_CRASH(); }
++
++ void lowerAtomicLoad64(MLoadUnboxedScalar*) { MOZ_CRASH(); }
++ void lowerAtomicStore64(MStoreUnboxedScalar*) { MOZ_CRASH(); }
++
++ LTableSwitch* newLTableSwitch(LAllocation, LDefinition, MTableSwitch*) {
++ MOZ_CRASH();
++ }
++ LTableSwitchV* newLTableSwitchV(MTableSwitch*) { MOZ_CRASH(); }
++};
++
++typedef LIRGeneratorRiscv64 LIRGeneratorSpecific;
++
++} // namespace jit
++} // namespace js
++
++#endif /* jit_riscv64_Lowering_riscv64_h */
+diff --git a/js/src/jit/riscv64/MacroAssembler-riscv64-inl.h b/js/src/jit/riscv64/MacroAssembler-riscv64-inl.h
+new file mode 100644
+index 0000000000..3dd6273d0f
+--- /dev/null
++++ b/js/src/jit/riscv64/MacroAssembler-riscv64-inl.h
+@@ -0,0 +1,18 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
++ * vim: set ts=8 sts=2 et sw=2 tw=80:
++ * This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#ifndef jit_riscv64_MacroAssembler_riscv64_inl_h
++#define jit_riscv64_MacroAssembler_riscv64_inl_h
++
++#include "jit/riscv64/MacroAssembler-riscv64.h"
++
++namespace js {
++namespace jit {
++
++} // namespace jit
++} // namespace js
++
++#endif
+diff --git a/js/src/jit/riscv64/MacroAssembler-riscv64.h b/js/src/jit/riscv64/MacroAssembler-riscv64.h
+new file mode 100644
+index 0000000000..30ca17d359
+--- /dev/null
++++ b/js/src/jit/riscv64/MacroAssembler-riscv64.h
+@@ -0,0 +1,458 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
++ * vim: set ts=8 sts=2 et sw=2 tw=80:
++ * This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#ifndef jit_riscv64_MacroAssembler_riscv64_h
++#define jit_riscv64_MacroAssembler_riscv64_h
++
++#include "jit/riscv64/Assembler-riscv64.h"
++#include "jit/MoveResolver.h"
++#include "wasm/WasmBuiltins.h"
++
++namespace js {
++namespace jit {
++
++static constexpr ValueOperand JSReturnOperand{JSReturnReg};
++
++class ScratchTagScope : public SecondScratchRegisterScope {
++ public:
++ ScratchTagScope(MacroAssembler& masm, const js::jit::ValueOperand&)
++ : SecondScratchRegisterScope(masm) {}
++};
++
++class ScratchTagScopeRelease {
++ ScratchTagScope* ts_;
++
++ public:
++ explicit ScratchTagScopeRelease(ScratchTagScope* ts) : ts_(ts) {
++ ts_->release();
++ }
++
++ ~ScratchTagScopeRelease() { ts_->reacquire(); }
++};
++
++class MacroAssemblerRiscv64 : public Assembler {
++ protected:
++ // Perform a downcast. Should be removed by Bug 996602.
++ MacroAssembler& asMasm();
++ const MacroAssembler& asMasm() const;
++
++ public:
++ MacroAssemblerRiscv64() { MOZ_CRASH(); }
++
++ MoveResolver moveResolver_;
++
++ size_t size() const { MOZ_CRASH(); }
++ size_t bytesNeeded() const { MOZ_CRASH(); }
++ size_t jumpRelocationTableBytes() const { MOZ_CRASH(); }
++ size_t dataRelocationTableBytes() const { MOZ_CRASH(); }
++ size_t preBarrierTableBytes() const { MOZ_CRASH(); }
++
++ size_t numCodeLabels() const { MOZ_CRASH(); }
++ CodeLabel codeLabel(size_t) { MOZ_CRASH(); }
++
++ bool reserve(size_t size) { MOZ_CRASH(); }
++ bool appendRawCode(const uint8_t* code, size_t numBytes) { MOZ_CRASH(); }
++ bool swapBuffer(wasm::Bytes& bytes) { MOZ_CRASH(); }
++
++ void assertNoGCThings() const { MOZ_CRASH(); }
++
++ static bool SupportsFloatingPoint() { return false; }
++ static bool SupportsUnalignedAccesses() { return false; }
++ static bool SupportsFastUnalignedFPAccesses() { return false; }
++
++ void executableCopy(void*, bool = true) { MOZ_CRASH(); }
++ void copyJumpRelocationTable(uint8_t*) { MOZ_CRASH(); }
++ void copyDataRelocationTable(uint8_t*) { MOZ_CRASH(); }
++ void copyPreBarrierTable(uint8_t*) { MOZ_CRASH(); }
++ void processCodeLabels(uint8_t*) { MOZ_CRASH(); }
++
++ void flushBuffer() {}
++
++ template <typename T>
++ void bind(T) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void j(Condition, T) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void jump(T) {
++ MOZ_CRASH();
++ }
++ void writeCodePointer(CodeLabel* label) {
++ MOZ_CRASH();
++ }
++ void haltingAlign(size_t) { MOZ_CRASH(); }
++ void nopAlign(size_t) { MOZ_CRASH(); }
++ void checkStackAlignment() { MOZ_CRASH(); }
++ uint32_t currentOffset() { return nextOffset().getOffset(); }
++
++ void nop() { MOZ_CRASH(); }
++ void breakpoint() { MOZ_CRASH(); }
++ void abiret() { MOZ_CRASH(); }
++ void ret() { MOZ_CRASH(); }
++
++ CodeOffset toggledJump(Label*) { MOZ_CRASH(); }
++ CodeOffset toggledCall(JitCode*, bool) { MOZ_CRASH(); }
++ static size_t ToggledCallSize(uint8_t*) { MOZ_CRASH(); }
++
++ void finish() { MOZ_CRASH(); }
++
++ template <typename T, typename S>
++ void moveValue(T, S) {
++ MOZ_CRASH();
++ }
++ template <typename T, typename S, typename U>
++ void moveValue(T, S, U) {
++ MOZ_CRASH();
++ }
++ template <typename T, typename S>
++ void storeValue(const T&, const S&) {
++ MOZ_CRASH();
++ }
++ template <typename T, typename S, typename U>
++ void storeValue(T, S, U) {
++ MOZ_CRASH();
++ }
++ template <typename T, typename S>
++ void storePrivateValue(const T&, const S&) {
++ MOZ_CRASH();
++ }
++ template <typename T, typename S>
++ void loadValue(T, S) {
++ MOZ_CRASH();
++ }
++ template <typename T, typename S>
++ void loadUnalignedValue(T, S) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void pushValue(const T&) {
++ MOZ_CRASH();
++ }
++ template <typename T, typename S>
++ void pushValue(T, S) {
++ MOZ_CRASH();
++ }
++ void popValue(ValueOperand) { MOZ_CRASH(); }
++ void tagValue(JSValueType, Register, ValueOperand) { MOZ_CRASH(); }
++ void retn(Imm32 n) { MOZ_CRASH(); }
++ template <typename T>
++ void push(const T&) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void Push(T) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void pop(T) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void Pop(T) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ CodeOffset pushWithPatch(T) {
++ MOZ_CRASH();
++ }
++
++ void testNullSet(Condition, ValueOperand, Register) { MOZ_CRASH(); }
++ void testObjectSet(Condition, ValueOperand, Register) { MOZ_CRASH(); }
++ void testUndefinedSet(Condition, ValueOperand, Register) { MOZ_CRASH(); }
++
++ template <typename T, typename S>
++ void cmpPtrSet(Condition, T, S, Register) {
++ MOZ_CRASH();
++ }
++ void cmp8Set(Condition, Address, Imm32, Register) { MOZ_CRASH(); }
++ void cmp16Set(Condition, Address, Imm32, Register) { MOZ_CRASH(); }
++ template <typename T, typename S>
++ void cmp32Set(Condition, T, S, Register) {
++ MOZ_CRASH();
++ }
++ void cmp64Set(Condition, Address, Imm64, Register) { MOZ_CRASH(); }
++
++ template <typename T>
++ void mov(T, Register) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void movePtr(T, Register) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void move32(const T&, Register) {
++ MOZ_CRASH();
++ }
++ template <typename T, typename S>
++ void movq(T, S) {
++ MOZ_CRASH();
++ }
++ template <typename T, typename S>
++ void moveFloat32(T, S) {
++ MOZ_CRASH();
++ }
++ template <typename T, typename S>
++ void moveDouble(T, S) {
++ MOZ_CRASH();
++ }
++ template <typename T, typename S>
++ void move64(T, S) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ CodeOffset movWithPatch(T, Register) {
++ MOZ_CRASH();
++ }
++
++ template <typename T>
++ void loadPtr(T, Register) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void load32(T, Register) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void load32Unaligned(T, Register) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void loadFloat32(T, FloatRegister) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void loadDouble(T, FloatRegister) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void loadPrivate(T, Register) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void load8SignExtend(T, Register) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void load8ZeroExtend(T, Register) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void load16SignExtend(T, Register) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void load16UnalignedSignExtend(T, Register) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void load16ZeroExtend(T, Register) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void load16UnalignedZeroExtend(T, Register) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void load64(T, Register64) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void load64Unaligned(T, Register64) {
++ MOZ_CRASH();
++ }
++
++ template <typename T, typename S>
++ void storePtr(const T&, S) {
++ MOZ_CRASH();
++ }
++ template <typename T, typename S>
++ void store32(T, S) {
++ MOZ_CRASH();
++ }
++ template <typename T, typename S>
++ void store32_NoSecondScratch(T, S) {
++ MOZ_CRASH();
++ }
++ template <typename T, typename S>
++ void store32Unaligned(T, S) {
++ MOZ_CRASH();
++ }
++ template <typename T, typename S>
++ void storeFloat32(T, S) {
++ MOZ_CRASH();
++ }
++ template <typename T, typename S>
++ void storeDouble(T, S) {
++ MOZ_CRASH();
++ }
++ template <typename T, typename S>
++ void store8(T, S) {
++ MOZ_CRASH();
++ }
++ template <typename T, typename S>
++ void store16(T, S) {
++ MOZ_CRASH();
++ }
++ template <typename T, typename S>
++ void store16Unaligned(T, S) {
++ MOZ_CRASH();
++ }
++ template <typename T, typename S>
++ void store64(T, S) {
++ MOZ_CRASH();
++ }
++ template <typename T, typename S>
++ void store64Unaligned(T, S) {
++ MOZ_CRASH();
++ }
++
++ template <typename T>
++ void computeEffectiveAddress(T, Register) {
++ MOZ_CRASH();
++ }
++
++ void splitTagForTest(ValueOperand, ScratchTagScope&) { MOZ_CRASH(); }
++
++ void boxDouble(FloatRegister, ValueOperand, FloatRegister) { MOZ_CRASH(); }
++ void boxNonDouble(JSValueType, Register, ValueOperand) { MOZ_CRASH(); }
++ template <typename T>
++ void boxDouble(FloatRegister src, const T& dest) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void unboxInt32(T, Register) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void unboxBoolean(T, Register) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void unboxString(T, Register) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void unboxSymbol(T, Register) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void unboxBigInt(T, Register) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void unboxObject(T, Register) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void unboxDouble(T, FloatRegister) {
++ MOZ_CRASH();
++ }
++ void unboxValue(const ValueOperand&, AnyRegister, JSValueType) {
++ MOZ_CRASH();
++ }
++ void unboxNonDouble(const ValueOperand&, Register, JSValueType) {
++ MOZ_CRASH();
++ }
++ void unboxNonDouble(const Address&, Register, JSValueType) { MOZ_CRASH(); }
++ template <typename T>
++ void unboxGCThingForGCBarrier(const T&, Register) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void unboxObjectOrNull(const T& src, Register dest) {
++ MOZ_CRASH();
++ }
++ void notBoolean(ValueOperand) { MOZ_CRASH(); }
++ [[nodiscard]] Register extractObject(Address, Register) { MOZ_CRASH(); }
++ [[nodiscard]] Register extractObject(ValueOperand, Register) { MOZ_CRASH(); }
++ [[nodiscard]] Register extractSymbol(ValueOperand, Register) { MOZ_CRASH(); }
++ [[nodiscard]] Register extractInt32(ValueOperand, Register) { MOZ_CRASH(); }
++ [[nodiscard]] Register extractBoolean(ValueOperand, Register) { MOZ_CRASH(); }
++ template <typename T>
++ [[nodiscard]] Register extractTag(T, Register) {
++ MOZ_CRASH();
++ }
++
++ void convertFloat32ToInt32(FloatRegister, Register, Label*, bool v = true) {
++ MOZ_CRASH();
++ }
++ void convertDoubleToInt32(FloatRegister, Register, Label*, bool v = true) {
++ MOZ_CRASH();
++ }
++ void convertDoubleToPtr(FloatRegister, Register, Label*, bool v = true) {
++ MOZ_CRASH();
++ }
++ void convertBoolToInt32(Register, Register) { MOZ_CRASH(); }
++
++ void convertDoubleToFloat32(FloatRegister, FloatRegister) { MOZ_CRASH(); }
++ void convertInt32ToFloat32(Register, FloatRegister) { MOZ_CRASH(); }
++
++ template <typename T>
++ void convertInt32ToDouble(T, FloatRegister) {
++ MOZ_CRASH();
++ }
++ void convertFloat32ToDouble(FloatRegister, FloatRegister) { MOZ_CRASH(); }
++
++ void boolValueToDouble(ValueOperand, FloatRegister) { MOZ_CRASH(); }
++ void boolValueToFloat32(ValueOperand, FloatRegister) { MOZ_CRASH(); }
++ void int32ValueToDouble(ValueOperand, FloatRegister) { MOZ_CRASH(); }
++ void int32ValueToFloat32(ValueOperand, FloatRegister) { MOZ_CRASH(); }
++
++ void loadConstantDouble(double, FloatRegister) { MOZ_CRASH(); }
++ void loadConstantFloat32(float, FloatRegister) { MOZ_CRASH(); }
++ Condition testInt32Truthy(bool, ValueOperand) { MOZ_CRASH(); }
++ Condition testStringTruthy(bool, ValueOperand) { MOZ_CRASH(); }
++ Condition testBigIntTruthy(bool, ValueOperand) { MOZ_CRASH(); }
++
++ template <typename T>
++ void loadUnboxedValue(T, MIRType, AnyRegister) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void storeUnboxedValue(const ConstantOrRegister&, MIRType, T, MIRType) {
++ MOZ_CRASH();
++ }
++ template <typename T>
++ void storeUnboxedPayload(ValueOperand value, T, size_t, JSValueType) {
++ MOZ_CRASH();
++ }
++
++ void convertUInt32ToDouble(Register, FloatRegister) { MOZ_CRASH(); }
++ void convertUInt32ToFloat32(Register, FloatRegister) { MOZ_CRASH(); }
++ void incrementInt32Value(Address) { MOZ_CRASH(); }
++ void ensureDouble(ValueOperand, FloatRegister, Label*) { MOZ_CRASH(); }
++
++ void buildFakeExitFrame(Register, uint32_t*) { MOZ_CRASH(); }
++ bool buildOOLFakeExitFrame(void*) { MOZ_CRASH(); }
++
++ void setPrinter(Sprinter*) { MOZ_CRASH(); }
++ Operand ToPayload(Operand base) { MOZ_CRASH(); }
++ Address ToPayload(Address) { MOZ_CRASH(); }
++
++ Register getStackPointer() const { MOZ_CRASH(); }
++
++ void handleFailureWithHandlerTail(Label* profilerExitTail,
++ Label* bailoutTail) { MOZ_CRASH(); }
++
++ // Instrumentation for entering and leaving the profiler.
++ void profilerEnterFrame(Register, Register) { MOZ_CRASH(); }
++ void profilerExitFrame() { MOZ_CRASH(); }
++};
++
++typedef MacroAssemblerRiscv64 MacroAssemblerSpecific;
++
++static inline bool GetTempRegForIntArg(uint32_t, uint32_t, Register*) {
++ MOZ_CRASH();
++}
++
++} // namespace jit
++} // namespace js
++
++#endif /* jit_riscv64_MacroAssembler_riscv64_h */
+diff --git a/js/src/jit/riscv64/MoveEmitter-riscv64.h b/js/src/jit/riscv64/MoveEmitter-riscv64.h
+new file mode 100644
+index 0000000000..24ca3aebb2
+--- /dev/null
++++ b/js/src/jit/riscv64/MoveEmitter-riscv64.h
+@@ -0,0 +1,32 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
++ * vim: set ts=8 sts=2 et sw=2 tw=80:
++ * This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#ifndef jit_riscv64_MoveEmitter_riscv64_h
++#define jit_riscv64_MoveEmitter_riscv64_h
++
++#include "mozilla/Assertions.h"
++
++namespace js {
++namespace jit {
++
++class MacroAssemblerRiscv64;
++class MoveResolver;
++struct Register;
++
++class MoveEmitterRiscv64 {
++ public:
++ explicit MoveEmitterRiscv64(MacroAssemblerRiscv64&) { MOZ_CRASH(); }
++ void emit(const MoveResolver&) { MOZ_CRASH(); }
++ void finish() { MOZ_CRASH(); }
++ void setScratchRegister(Register) { MOZ_CRASH(); }
++};
++
++typedef MoveEmitterRiscv64 MoveEmitter;
++
++} // namespace jit
++} // namespace js
++
++#endif /* jit_riscv64_MoveEmitter_riscv64_h */
+diff --git a/js/src/jit/riscv64/SharedICHelpers-riscv64-inl.h b/js/src/jit/riscv64/SharedICHelpers-riscv64-inl.h
+new file mode 100644
+index 0000000000..7c6f7b7c20
+--- /dev/null
++++ b/js/src/jit/riscv64/SharedICHelpers-riscv64-inl.h
+@@ -0,0 +1,34 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
++ * vim: set ts=8 sts=2 et sw=2 tw=80:
++ * This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#ifndef jit_riscv64_SharedICHelpers_riscv64_inl_h
++#define jit_riscv64_SharedICHelpers_riscv64_inl_h
++
++#include "jit/SharedICHelpers.h"
++
++namespace js {
++namespace jit {
++
++inline void EmitBaselineTailCallVM(TrampolinePtr, MacroAssembler&, uint32_t) {
++ MOZ_CRASH();
++}
++inline void EmitBaselineCreateStubFrameDescriptor(MacroAssembler&, Register,
++ uint32_t) {
++ MOZ_CRASH();
++}
++inline void EmitBaselineCallVM(TrampolinePtr, MacroAssembler&) { MOZ_CRASH(); }
++
++static const uint32_t STUB_FRAME_SIZE = 0;
++static const uint32_t STUB_FRAME_SAVED_STUB_OFFSET = 0;
++
++inline void EmitBaselineEnterStubFrame(MacroAssembler&, Register) {
++ MOZ_CRASH();
++}
++
++} // namespace jit
++} // namespace js
++
++#endif /* jit_riscv64_SharedICHelpers_riscv64_inl_h */
+diff --git a/js/src/jit/riscv64/SharedICHelpers-riscv64.h b/js/src/jit/riscv64/SharedICHelpers-riscv64.h
+new file mode 100644
+index 0000000000..205b6615da
+--- /dev/null
++++ b/js/src/jit/riscv64/SharedICHelpers-riscv64.h
+@@ -0,0 +1,35 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
++ * vim: set ts=8 sts=2 et sw=2 tw=80:
++ * This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#ifndef jit_riscv64_SharedICHelpers_riscv64_h
++#define jit_riscv64_SharedICHelpers_riscv64_h
++
++#include "jit/MacroAssembler.h"
++#include "jit/SharedICRegisters.h"
++
++namespace js {
++namespace jit {
++
++static const size_t ICStackValueOffset = 0;
++
++inline void EmitRestoreTailCallReg(MacroAssembler&) { MOZ_CRASH(); }
++inline void EmitRepushTailCallReg(MacroAssembler&) { MOZ_CRASH(); }
++inline void EmitCallIC(MacroAssembler&, CodeOffset*) { MOZ_CRASH(); }
++inline void EmitReturnFromIC(MacroAssembler&) { MOZ_CRASH(); }
++inline void EmitBaselineLeaveStubFrame(MacroAssembler&, bool v = false) {
++ MOZ_CRASH();
++}
++inline void EmitStubGuardFailure(MacroAssembler&) { MOZ_CRASH(); }
++
++template <typename T>
++inline void EmitPreBarrier(MacroAssembler&, T, MIRType) {
++ MOZ_CRASH();
++}
++
++} // namespace jit
++} // namespace js
++
++#endif /* jit_riscv64_SharedICHelpers_riscv64_h */
+diff --git a/js/src/jit/riscv64/SharedICRegisters-riscv64.h b/js/src/jit/riscv64/SharedICRegisters-riscv64.h
+new file mode 100644
+index 0000000000..f1d5f165d8
+--- /dev/null
++++ b/js/src/jit/riscv64/SharedICRegisters-riscv64.h
+@@ -0,0 +1,38 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
++ * vim: set ts=8 sts=2 et sw=2 tw=80:
++ * This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#ifndef jit_riscv64_SharedICRegisters_riscv64_h
++#define jit_riscv64_SharedICRegisters_riscv64_h
++
++#include "jit/riscv64/Assembler-riscv64.h"
++#include "jit/Registers.h"
++#include "jit/RegisterSets.h"
++
++namespace js {
++namespace jit {
++
++static constexpr Register BaselineFrameReg{Registers::invalid_reg};
++static constexpr Register BaselineStackReg{Registers::invalid_reg};
++
++static constexpr ValueOperand R0 = JSReturnOperand;
++static constexpr ValueOperand R1 = JSReturnOperand;
++static constexpr ValueOperand R2 = JSReturnOperand;
++
++static constexpr Register ICTailCallReg{Registers::invalid_reg};
++static constexpr Register ICStubReg{Registers::invalid_reg};
++
++static constexpr Register ExtractTemp0{Registers::invalid_reg};
++static constexpr Register ExtractTemp1{Registers::invalid_reg};
++
++static constexpr FloatRegister FloatReg0;
++static constexpr FloatRegister FloatReg1;
++static constexpr FloatRegister FloatReg2;
++static constexpr FloatRegister FloatReg3;
++
++} // namespace jit
++} // namespace js
++
++#endif /* jit_riscv64_SharedICRegisters_riscv64_h */
+diff --git a/js/src/jit/riscv64/Trampoline-riscv64.cpp b/js/src/jit/riscv64/Trampoline-riscv64.cpp
+new file mode 100644
+index 0000000000..0774254cf4
+--- /dev/null
++++ b/js/src/jit/riscv64/Trampoline-riscv64.cpp
+@@ -0,0 +1,67 @@
++/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
++ * vim: set ts=8 sts=2 et sw=2 tw=80:
++ * This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
++
++#include "jit/Bailouts.h"
++#include "jit/BaselineIC.h"
++#include "jit/JitRuntime.h"
++#include "vm/Realm.h"
++
++using namespace js;
++using namespace js::jit;
++
++// This file includes stubs for generating the JIT trampolines when there is no
++// JIT backend, and also includes implementations for assorted random things
++// which can't be implemented in headers.
++
++void JitRuntime::generateEnterJIT(JSContext*, MacroAssembler&) { MOZ_CRASH(); }
++// static
++mozilla::Maybe<::JS::ProfilingFrameIterator::RegisterState>
++JitRuntime::getCppEntryRegisters(JitFrameLayout* frameStackAddress) {
++ return mozilla::Nothing{};
++}
++void JitRuntime::generateInvalidator(MacroAssembler&, Label*) { MOZ_CRASH(); }
++void JitRuntime::generateArgumentsRectifier(MacroAssembler&,
++ ArgumentsRectifierKind kind) {
++ MOZ_CRASH();
++}
++JitRuntime::BailoutTable JitRuntime::generateBailoutTable(MacroAssembler&,
++ Label*, uint32_t) {
++ MOZ_CRASH();
++}
++void JitRuntime::generateBailoutHandler(MacroAssembler&, Label*) {
++ MOZ_CRASH();
++}
++uint32_t JitRuntime::generatePreBarrier(JSContext*, MacroAssembler&, MIRType) {
++ MOZ_CRASH();
++}
++void JitRuntime::generateExceptionTailStub(MacroAssembler&, Label*) {
++ MOZ_CRASH();
++}
++void JitRuntime::generateBailoutTailStub(MacroAssembler&, Label*) {
++ MOZ_CRASH();
++}
++void JitRuntime::generateProfilerExitFrameTailStub(MacroAssembler&, Label*) {
++ MOZ_CRASH();
++}
++
++bool JitRuntime::generateVMWrapper(JSContext*, MacroAssembler&,
++ const VMFunctionData&, DynFn, uint32_t*) {
++ MOZ_CRASH();
++}
++
++FrameSizeClass FrameSizeClass::FromDepth(uint32_t) { MOZ_CRASH(); }
++FrameSizeClass FrameSizeClass::ClassLimit() { MOZ_CRASH(); }
++uint32_t FrameSizeClass::frameSize() const { MOZ_CRASH(); }
++
++BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator& iter,
++ BailoutStack* bailout) {
++ MOZ_CRASH();
++}
++
++BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator& iter,
++ InvalidationBailoutStack* bailout) {
++ MOZ_CRASH();
++}
+diff --git a/js/src/jit/shared/Assembler-shared.h b/js/src/jit/shared/Assembler-shared.h
+index fcabddd98b..19cf397df1 100644
+--- a/js/src/jit/shared/Assembler-shared.h
++++ b/js/src/jit/shared/Assembler-shared.h
+@@ -26,13 +26,14 @@
+
+ #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
+ defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \
+- defined(JS_CODEGEN_LOONG64)
++ defined(JS_CODEGEN_LOONG64) || defined(JS_CODEGEN_RISCV64)
+ // Push return addresses callee-side.
+ # define JS_USE_LINK_REGISTER
+ #endif
+
+ #if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \
+- defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_LOONG64)
++ defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_LOONG64) || \
++ defined(JS_CODEGEN_RISCV64)
+ // JS_CODELABEL_LINKMODE gives labels additional metadata
+ // describing how Bind() should patch them.
+ # define JS_CODELABEL_LINKMODE
+diff --git a/js/src/util/Poison.h b/js/src/util/Poison.h
+index cb8e1abc64..a6a2d2f12b 100644
+--- a/js/src/util/Poison.h
++++ b/js/src/util/Poison.h
+@@ -95,6 +95,8 @@ const uint8_t JS_SCOPE_DATA_TRAILING_NAMES_PATTERN = 0xCC;
+ # define JS_SWEPT_CODE_PATTERN 0x01 // undefined instruction
+ #elif defined(JS_CODEGEN_LOONG64)
+ # define JS_SWEPT_CODE_PATTERN 0x01 // undefined instruction
++#elif defined(JS_CODEGEN_RISCV64)
++# define JS_SWEPT_CODE_PATTERN 0x01 // undefined instruction
+ #else
+ # error "JS_SWEPT_CODE_PATTERN not defined for this platform"
+ #endif
+diff --git a/js/src/wasm/WasmBCMemory.cpp b/js/src/wasm/WasmBCMemory.cpp
+index 94e739090b..2c226dadd5 100644
+--- a/js/src/wasm/WasmBCMemory.cpp
++++ b/js/src/wasm/WasmBCMemory.cpp
+@@ -1214,6 +1214,22 @@ static void Deallocate(BaseCompiler* bc, RegI32 rv, const Temps& temps) {
+ bc->maybeFree(temps.t2);
+ }
+
++#elif defined(JS_CODEGEN_RISCV64)
++
++struct Temps {
++ RegI32 t0;
++};
++
++static void PopAndAllocate(BaseCompiler* bc, ValType type,
++ Scalar::Type viewType, AtomicOp op, RegI32* rd,
++ RegI32* rv, Temps* temps) {}
++
++static void Perform(BaseCompiler* bc, const MemoryAccessDesc& access,
++ BaseIndex srcAddr, AtomicOp op, RegI32 rv, RegI32 rd,
++ const Temps& temps) {}
++
++static void Deallocate(BaseCompiler*, RegI32, const Temps&) {}
++
+ #elif defined(JS_CODEGEN_NONE)
+
+ using Temps = Nothing;
+@@ -1375,6 +1391,17 @@ static void Deallocate(BaseCompiler* bc, AtomicOp op, RegI64 rv, RegI64 temp) {
+ bc->freeI64(temp);
+ }
+
++#elif defined(JS_CODEGEN_RISCV64)
++
++static void PopAndAllocate(BaseCompiler* bc, AtomicOp op, RegI64* rd,
++ RegI64* rv, RegI64* temp) {}
++
++static void Perform(BaseCompiler* bc, const MemoryAccessDesc& access,
++ BaseIndex srcAddr, AtomicOp op, RegI64 rv, RegI64 temp,
++ RegI64 rd) {}
++
++static void Deallocate(BaseCompiler* bc, AtomicOp op, RegI64 rv, RegI64 temp) {}
++
+ #elif defined(JS_CODEGEN_NONE)
+
+ static void PopAndAllocate(BaseCompiler*, AtomicOp, RegI64*, RegI64*, RegI64*) {
+diff --git a/js/src/wasm/WasmCompile.cpp b/js/src/wasm/WasmCompile.cpp
+index 26534bca4e..403e26414b 100644
+--- a/js/src/wasm/WasmCompile.cpp
++++ b/js/src/wasm/WasmCompile.cpp
+@@ -74,6 +74,8 @@ uint32_t wasm::ObservedCPUFeatures() {
+ #elif defined(JS_CODEGEN_LOONG64)
+ MOZ_ASSERT(jit::GetLOONG64Flags() <= (UINT32_MAX >> ARCH_BITS));
+ return LOONG64 | (jit::GetLOONG64Flags() << ARCH_BITS);
++#elif defined(JS_CODEGEN_RISCV64)
++ return 0;
+ #elif defined(JS_CODEGEN_NONE)
+ return 0;
+ #else
+diff --git a/js/src/wasm/WasmFrameIter.cpp b/js/src/wasm/WasmFrameIter.cpp
+index e612e05704..0ce3453287 100644
+--- a/js/src/wasm/WasmFrameIter.cpp
++++ b/js/src/wasm/WasmFrameIter.cpp
+@@ -384,6 +384,12 @@ static const unsigned PushedFP = 16;
+ static const unsigned SetFP = 20;
+ static const unsigned PoppedFP = 4;
+ static const unsigned PoppedFPJitEntry = 0;
++#elif defined(JS_CODEGEN_RISCV64)
++static const unsigned PushedRetAddr = 0;
++static const unsigned PushedFP = 1;
++static const unsigned SetFP = 2;
++static const unsigned PoppedFP = 3;
++static const unsigned PoppedFPJitEntry = 4;
+ #elif defined(JS_CODEGEN_NONE)
+ // Synthetic values to satisfy asserts and avoid compiler warnings.
+ static const unsigned PushedRetAddr = 0;
+diff --git a/js/src/wasm/WasmSignalHandlers.cpp b/js/src/wasm/WasmSignalHandlers.cpp
+index f74368b954..9521441f02 100644
+--- a/js/src/wasm/WasmSignalHandlers.cpp
++++ b/js/src/wasm/WasmSignalHandlers.cpp
+@@ -157,6 +157,11 @@ using mozilla::DebugOnly;
+ # 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
+ # if defined(__linux__) && defined(__loongarch__)
+ # define EPC_sig(p) ((p)->uc_mcontext.pc)
+ # define RRA_sig(p) ((p)->uc_mcontext.gregs[1])
+@@ -405,6 +410,10 @@ struct macos_aarch64_context {
+ # define FP_sig(p) RFP_sig(p)
+ # define SP_sig(p) RSP_sig(p)
+ # define LR_sig(p) RRA_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) {
+diff --git a/python/mozbuild/mozbuild/vendor/vendor_rust.py b/python/mozbuild/mozbuild/vendor/vendor_rust.py
+index 31baea4290..7394ccaf40 100644
+--- a/python/mozbuild/mozbuild/vendor/vendor_rust.py
++++ b/python/mozbuild/mozbuild/vendor/vendor_rust.py
+@@ -98,6 +98,7 @@ TOLERATED_DUPES = {
+ "libloading": 2,
+ "memoffset": 2,
+ "mio": 2,
++ "nix": 2,
+ # Transition from time 0.1 to 0.3 underway, but chrono is stuck on 0.1
+ # and hasn't been updated in 1.5 years (an hypothetical update is
+ # expected to remove the dependency on time altogether).
+diff --git a/supply-chain/config.toml b/supply-chain/config.toml
+index bb3dd733e8..371cbca809 100644
+--- a/supply-chain/config.toml
++++ b/supply-chain/config.toml
+@@ -1,6 +1,10 @@
+
+ # cargo-vet config file
+
++[policy.viaduct]
++audit-as-crates-io = true
++notes = "I don't know, do as what rust-vet tells me to do"
++
+ [policy.async-task]
+ audit-as-crates-io = true
+ notes = "This is the upstream code plus an extra fix that hasn't been released yet, see bug 1746533."
+diff --git a/toolkit/library/rust/shared/Cargo.toml b/toolkit/library/rust/shared/Cargo.toml
+index dbd7770326..ffbadcb14c 100644
+--- a/toolkit/library/rust/shared/Cargo.toml
++++ b/toolkit/library/rust/shared/Cargo.toml
+@@ -38,7 +38,7 @@ tokio-reactor = { version = "=0.1.3", optional = true }
+ # audioipc2-client and audioipc2-server.
+ tokio-threadpool = { version = "=0.1.17", optional = true }
+ encoding_glue = { path = "../../../../intl/encoding_glue" }
+-authenticator = "0.3.1"
++authenticator = { git = "https://github.com/mozilla/authenticator-rs", rev = "b85bccf0527e42c877573029e8d35ff13ef06f9d" }
+ gkrust_utils = { path = "../../../../xpcom/rust/gkrust_utils" }
+ gecko_logger = { path = "../../../../xpcom/rust/gecko_logger" }
+ rsdparsa_capi = { path = "../../../../dom/media/webrtc/sdp/rsdparsa_capi" }
+@@ -72,6 +72,7 @@ midir_impl = { path = "../../../../dom/midi/midir_impl", optional = true }
+ dom = { path = "../../../../dom/base/rust" }
+ origin-trials-ffi = { path = "../../../../dom/origin-trials/ffi" }
+ jog = { path = "../../../components/glean/bindings/jog" }
++midir = { version = "0.8.0" }
+
+ # Note: `modern_sqlite` means rusqlite's bindings file be for a sqlite with
+ # version less than or equal to what we link to. This isn't a problem because we
diff --git a/www-client/firefox/files/firefox-wayland.sh b/www-client/firefox/files/firefox-wayland.sh
deleted file mode 100644
index 4428025..0000000
--- a/www-client/firefox/files/firefox-wayland.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/sh
-
-#
-# Run Mozilla Firefox under Wayland
-#
-export MOZ_ENABLE_WAYLAND=1
-exec @PREFIX@/bin/firefox "$@"
diff --git a/www-client/firefox/files/firefox-x11.sh b/www-client/firefox/files/firefox-x11.sh
deleted file mode 100644
index 7565566..0000000
--- a/www-client/firefox/files/firefox-x11.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/sh
-
-#
-# Run Mozilla Firefox on X11
-#
-export MOZ_DISABLE_WAYLAND=1
-exec @PREFIX@/bin/firefox "$@"
diff --git a/www-client/firefox/files/firefox.sh b/www-client/firefox/files/firefox.sh
deleted file mode 100644
index c08d555..0000000
--- a/www-client/firefox/files/firefox.sh
+++ /dev/null
@@ -1,128 +0,0 @@
-#!/bin/bash
-
-##
-## Usage:
-##
-## $ firefox
-##
-## This script is meant to run Mozilla Firefox in Gentoo.
-
-cmdname=$(basename "$0")
-
-##
-## Variables
-##
-MOZ_ARCH=$(uname -m)
-case ${MOZ_ARCH} in
- x86_64|s390x|sparc64)
- MOZ_LIB_DIR="@PREFIX@/lib64"
- SECONDARY_LIB_DIR="@PREFIX@/lib"
- ;;
- *)
- MOZ_LIB_DIR="@PREFIX@/lib"
- SECONDARY_LIB_DIR="@PREFIX@/lib64"
- ;;
-esac
-
-MOZ_FIREFOX_FILE="firefox"
-
-if [[ ! -r ${MOZ_LIB_DIR}/firefox/${MOZ_FIREFOX_FILE} ]]; then
- if [[ ! -r ${SECONDARY_LIB_DIR}/firefox/${MOZ_FIREFOX_FILE} ]]; then
- echo "Error: ${MOZ_LIB_DIR}/firefox/${MOZ_FIREFOX_FILE} not found" >&2
- if [[ -d $SECONDARY_LIB_DIR ]]; then
- echo " ${SECONDARY_LIB_DIR}/firefox/${MOZ_FIREFOX_FILE} not found" >&2
- fi
- exit 1
- fi
- MOZ_LIB_DIR="$SECONDARY_LIB_DIR"
-fi
-MOZILLA_FIVE_HOME="${MOZ_LIB_DIR}/firefox"
-MOZ_EXTENSIONS_PROFILE_DIR="${HOME}/.mozilla/extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"
-MOZ_PROGRAM="${MOZILLA_FIVE_HOME}/${MOZ_FIREFOX_FILE}"
-DESKTOP_FILE="firefox"
-
-##
-## Enable Wayland backend?
-##
-if @DEFAULT_WAYLAND@ && [[ -z ${MOZ_DISABLE_WAYLAND} ]]; then
- if [[ -n "$WAYLAND_DISPLAY" ]]; then
- DESKTOP_FILE="firefox-wayland"
- export MOZ_ENABLE_WAYLAND=1
- fi
-elif [[ -n ${MOZ_DISABLE_WAYLAND} ]]; then
- DESKTOP_FILE="firefox-x11"
-fi
-
-##
-## Use D-Bus remote exclusively when there's Wayland display.
-##
-if [[ -n "${WAYLAND_DISPLAY}" ]]; then
- export MOZ_DBUS_REMOTE=1
-fi
-
-##
-## Make sure that we set the plugin path
-##
-MOZ_PLUGIN_DIR="plugins"
-
-if [[ -n "${MOZ_PLUGIN_PATH}" ]]; then
- MOZ_PLUGIN_PATH=${MOZ_PLUGIN_PATH}:${MOZ_LIB_DIR}/mozilla/${MOZ_PLUGIN_DIR}
-else
- MOZ_PLUGIN_PATH=${MOZ_LIB_DIR}/mozilla/${MOZ_PLUGIN_DIR}
-fi
-
-if [[ -d "${SECONDARY_LIB_DIR}/mozilla/${MOZ_PLUGIN_DIR}" ]]; then
- MOZ_PLUGIN_PATH=${MOZ_PLUGIN_PATH}:${SECONDARY_LIB_DIR}/mozilla/${MOZ_PLUGIN_DIR}
-fi
-
-export MOZ_PLUGIN_PATH
-
-##
-## Set MOZ_APP_LAUNCHER for gnome-session
-##
-export MOZ_APP_LAUNCHER="@PREFIX@/bin/${cmdname}"
-
-##
-## Disable the GNOME crash dialog, Moz has it's own
-##
-if [[ "$XDG_CURRENT_DESKTOP" == "GNOME" ]]; then
- GNOME_DISABLE_CRASH_DIALOG=1
- export GNOME_DISABLE_CRASH_DIALOG
-fi
-
-##
-## Enable Xinput2 (#617344)
-##
-
-# respect user settings
-MOZ_USE_XINPUT2=${MOZ_USE_XINPUT2:-auto}
-
-if [[ ${MOZ_USE_XINPUT2} == auto && -n ${WAYLAND_DISPLAY} ]]; then
- # enabling XINPUT2 should be safe for all wayland users
- MOZ_USE_XINPUT2=1
-elif [[ ${MOZ_USE_XINPUT2} == auto && ${XDG_CURRENT_DESKTOP^^} == KDE ]]; then
- # XINPUT2 is known to cause problems for KWin users
- MOZ_USE_XINPUT2=0
-elif [[ ${MOZ_USE_XINPUT2} == auto && ${XDG_CURRENT_DESKTOP^^} == LXQT ]]; then
- # LXQt uses KWin
- MOZ_USE_XINPUT2=0
-elif [[ ${MOZ_USE_XINPUT2} == auto ]]; then
- # should work on Mate, Xfce, FluxBox, OpenBox and all the others ...
- MOZ_USE_XINPUT2=1
-fi
-
-[[ ${MOZ_USE_XINPUT2} != 0 ]] && export MOZ_USE_XINPUT2=${MOZ_USE_XINPUT2}
-
-# Don't throw "old profile" dialog box.
-export MOZ_ALLOW_DOWNGRADE=1
-
-##
-## Route to the correct .desktop file to get proper
-## name and actions
-##
-if [[ $@ != *"--name "* ]]; then
- set -- --name "${DESKTOP_FILE}" "$@"
-fi
-
-# Run the browser
-exec ${MOZ_PROGRAM} "$@"
diff --git a/www-client/firefox/files/gentoo-hwaccel-prefs.js-r2 b/www-client/firefox/files/gentoo-hwaccel-prefs.js-r2
new file mode 100644
index 0000000..48025ca
--- /dev/null
+++ b/www-client/firefox/files/gentoo-hwaccel-prefs.js-r2
@@ -0,0 +1,5 @@
+/* Force hardware accelerated rendering due to USE=hwaccel */
+pref("gfx.webrender.all", true);
+pref("layers.acceleration.force-enabled", true);
+pref("media.hardware-video-decoding.enabled", true);
+pref("webgl.force-enabled", true);
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
deleted file mode 100644
index 39ebd6a..0000000
--- a/www-client/firefox/files/makotokato-riscv64-support-and-zenithal-backported.patch
+++ /dev/null
@@ -1,47126 +0,0 @@
-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>(),
-+ ®s 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(), ×[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(), ×[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, ×[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(),
-+ ×[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) -> ×pec {
-+ &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) -> ×pec {
-@@ -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-103.0.1.ebuild b/www-client/firefox/firefox-103.0.1.ebuild
new file mode 100644
index 0000000..d0494bb
--- /dev/null
+++ b/www-client/firefox/firefox-103.0.1.ebuild
@@ -0,0 +1,1301 @@
+# Copyright 1999-2022 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI="8"
+
+FIREFOX_PATCHSET="firefox-103-patches-03j.tar.xz"
+
+LLVM_MAX_SLOT=14
+
+PYTHON_COMPAT=( python3_{8..11} )
+PYTHON_REQ_USE="ncurses,sqlite,ssl"
+
+WANT_AUTOCONF="2.1"
+
+VIRTUALX_REQUIRED="pgo"
+
+MOZ_ESR=
+
+MOZ_PV=${PV}
+MOZ_PV_SUFFIX=
+if [[ ${PV} =~ (_(alpha|beta|rc).*)$ ]] ; then
+ MOZ_PV_SUFFIX=${BASH_REMATCH[1]}
+
+ # Convert the ebuild version to the upstream Mozilla version
+ MOZ_PV="${MOZ_PV/_alpha/a}" # Handle alpha for SRC_URI
+ MOZ_PV="${MOZ_PV/_beta/b}" # Handle beta for SRC_URI
+ MOZ_PV="${MOZ_PV%%_rc*}" # Handle rc for SRC_URI
+fi
+
+if [[ -n ${MOZ_ESR} ]] ; then
+ # ESR releases have slightly different version numbers
+ MOZ_PV="${MOZ_PV}esr"
+fi
+
+MOZ_PN="${PN%-bin}"
+MOZ_P="${MOZ_PN}-${MOZ_PV}"
+MOZ_PV_DISTFILES="${MOZ_PV}${MOZ_PV_SUFFIX}"
+MOZ_P_DISTFILES="${MOZ_PN}-${MOZ_PV_DISTFILES}"
+
+inherit autotools check-reqs desktop flag-o-matic gnome2-utils linux-info \
+ llvm multiprocessing pax-utils python-any-r1 toolchain-funcs \
+ virtualx xdg
+
+MOZ_SRC_BASE_URI="https://archive.mozilla.org/pub/${MOZ_PN}/releases/${MOZ_PV}"
+
+if [[ ${PV} == *_rc* ]] ; then
+ MOZ_SRC_BASE_URI="https://archive.mozilla.org/pub/${MOZ_PN}/candidates/${MOZ_PV}-candidates/build${PV##*_rc}"
+fi
+
+PATCH_URIS=(
+ https://dev.gentoo.org/~{juippis,whissi,slashbeast}/mozilla/patchsets/${FIREFOX_PATCHSET}
+)
+
+SRC_URI="${MOZ_SRC_BASE_URI}/source/${MOZ_P}.source.tar.xz -> ${MOZ_P_DISTFILES}.source.tar.xz
+ ${PATCH_URIS[@]}"
+
+DESCRIPTION="Firefox Web Browser"
+HOMEPAGE="https://www.mozilla.com/firefox"
+
+KEYWORDS="~amd64 ~arm64 ~ppc64 ~riscv ~x86"
+
+SLOT="rapid"
+LICENSE="MPL-2.0 GPL-2 LGPL-2.1"
+
+# make clang non-default for now, as lld's relocation relax support is comming in llvm 15 release
+# https://reviews.llvm.org/D127611
+IUSE="clang cpu_flags_arm_neon dbus debug eme-free hardened hwaccel"
+IUSE+=" jack libproxy lto +openh264 pgo pulseaudio sndio selinux"
+IUSE+=" +system-av1 +system-harfbuzz +system-icu +system-jpeg +system-libevent +system-libvpx system-png system-python-libs +system-webp"
+IUSE+=" wayland wifi"
+
+# Firefox-only IUSE
+IUSE+=" geckodriver +gmp-autoupdate screencast +X"
+
+REQUIRED_USE="debug? ( !system-av1 )
+ pgo? ( lto )
+ wifi? ( dbus )"
+
+# Firefox-only REQUIRED_USE flags
+REQUIRED_USE+=" || ( X wayland )"
+REQUIRED_USE+=" pgo? ( X )"
+REQUIRED_USE+=" screencast? ( wayland )"
+
+BDEPEND="${PYTHON_DEPS}
+ app-arch/unzip
+ app-arch/zip
+ >=dev-util/cbindgen-0.24.3
+ net-libs/nodejs
+ virtual/pkgconfig
+ virtual/rust
+ || (
+ (
+ sys-devel/clang:14
+ sys-devel/llvm:14
+ clang? (
+ =sys-devel/lld-14*
+ pgo? ( =sys-libs/compiler-rt-sanitizers-14*[profile] )
+ )
+ )
+ (
+ sys-devel/clang:13
+ sys-devel/llvm:13
+ clang? (
+ =sys-devel/lld-13*
+ pgo? ( =sys-libs/compiler-rt-sanitizers-13*[profile] )
+ )
+ )
+ )
+ amd64? ( >=dev-lang/nasm-2.14 )
+ x86? ( >=dev-lang/nasm-2.14 )"
+
+COMMON_DEPEND="
+ dev-libs/atk
+ dev-libs/expat
+ dev-libs/glib:2
+ dev-libs/libffi:=
+ >=dev-libs/nss-3.80
+ >=dev-libs/nspr-4.34
+ media-libs/alsa-lib
+ media-libs/fontconfig
+ media-libs/freetype
+ media-libs/mesa
+ media-video/ffmpeg
+ sys-libs/zlib
+ virtual/freedesktop-icon-theme
+ x11-libs/cairo
+ x11-libs/gdk-pixbuf
+ x11-libs/pango
+ x11-libs/pixman
+ dbus? (
+ dev-libs/dbus-glib
+ sys-apps/dbus
+ )
+ jack? ( virtual/jack )
+ libproxy? ( net-libs/libproxy )
+ selinux? ( sec-policy/selinux-mozilla )
+ sndio? ( >=media-sound/sndio-1.8.0-r1 )
+ screencast? ( media-video/pipewire:= )
+ system-av1? (
+ >=media-libs/dav1d-0.9.3:=
+ >=media-libs/libaom-1.0.0:=
+ )
+ system-harfbuzz? (
+ >=media-gfx/graphite2-1.3.13
+ >=media-libs/harfbuzz-2.8.1:0=
+ )
+ system-icu? ( >=dev-libs/icu-71.1:= )
+ system-jpeg? ( >=media-libs/libjpeg-turbo-1.2.1 )
+ system-libevent? ( >=dev-libs/libevent-2.0:0=[threads] )
+ system-libvpx? ( >=media-libs/libvpx-1.8.2:0=[postproc] )
+ system-png? ( >=media-libs/libpng-1.6.35:0=[apng] )
+ system-webp? ( >=media-libs/libwebp-1.1.0:0= )
+ wayland? (
+ >=media-libs/libepoxy-1.5.10-r1
+ x11-libs/gtk+:3[wayland]
+ x11-libs/libdrm
+ x11-libs/libxkbcommon[wayland]
+ )
+ wifi? (
+ kernel_linux? (
+ dev-libs/dbus-glib
+ net-misc/networkmanager
+ sys-apps/dbus
+ )
+ )
+ X? (
+ virtual/opengl
+ x11-libs/cairo[X]
+ x11-libs/gtk+:3[X]
+ x11-libs/libX11
+ x11-libs/libXcomposite
+ x11-libs/libXdamage
+ x11-libs/libXext
+ x11-libs/libXfixes
+ x11-libs/libxkbcommon[X]
+ x11-libs/libXrandr
+ x11-libs/libXtst
+ x11-libs/libxcb:=
+ )"
+
+RDEPEND="${COMMON_DEPEND}
+ !www-client/firefox:0
+ !www-client/firefox:esr
+ jack? ( virtual/jack )
+ openh264? ( media-libs/openh264:*[plugin] )
+ pulseaudio? (
+ || (
+ media-sound/pulseaudio
+ >=media-sound/apulse-0.1.12-r4
+ )
+ )
+ selinux? ( sec-policy/selinux-mozilla )"
+
+DEPEND="${COMMON_DEPEND}
+ pulseaudio? (
+ || (
+ media-sound/pulseaudio
+ >=media-sound/apulse-0.1.12-r4[sdk]
+ )
+ )
+ X? (
+ x11-libs/libICE
+ x11-libs/libSM
+ )"
+
+S="${WORKDIR}/${PN}-${PV%_*}"
+RESTRICT=network-sandbox
+
+# Allow MOZ_GMP_PLUGIN_LIST to be set in an eclass or
+# overridden in the enviromnent (advanced hackers only)
+if [[ -z "${MOZ_GMP_PLUGIN_LIST+set}" ]] ; then
+ MOZ_GMP_PLUGIN_LIST=( gmp-gmpopenh264 gmp-widevinecdm )
+fi
+
+llvm_check_deps() {
+ if ! has_version -b "sys-devel/clang:${LLVM_SLOT}" ; then
+ einfo "sys-devel/clang:${LLVM_SLOT} is missing! Cannot use LLVM slot ${LLVM_SLOT} ..." >&2
+ return 1
+ fi
+
+ if use clang ; then
+ if ! has_version -b "=sys-devel/lld-${LLVM_SLOT}*" ; then
+ einfo "=sys-devel/lld-${LLVM_SLOT}* is missing! Cannot use LLVM slot ${LLVM_SLOT} ..." >&2
+ return 1
+ fi
+
+ if use pgo ; then
+ if ! has_version -b "=sys-libs/compiler-rt-sanitizers-${LLVM_SLOT}*" ; then
+ einfo "=sys-libs/compiler-rt-sanitizers-${LLVM_SLOT}* is missing! Cannot use LLVM slot ${LLVM_SLOT} ..." >&2
+ return 1
+ fi
+ fi
+ fi
+
+ einfo "Using LLVM slot ${LLVM_SLOT} to build" >&2
+}
+
+MOZ_LANGS=(
+ af ar ast be bg br ca cak cs cy da de dsb
+ el en-CA en-GB en-US es-AR es-ES et eu
+ fi fr fy-NL ga-IE gd gl he hr hsb hu
+ id is it ja ka kab kk ko lt lv ms nb-NO nl nn-NO
+ pa-IN pl pt-BR pt-PT rm ro ru
+ sk sl sq sr sv-SE th tr uk uz vi zh-CN zh-TW
+)
+
+# Firefox-only LANGS
+MOZ_LANGS+=( ach )
+MOZ_LANGS+=( an )
+MOZ_LANGS+=( az )
+MOZ_LANGS+=( bn )
+MOZ_LANGS+=( bs )
+MOZ_LANGS+=( ca-valencia )
+MOZ_LANGS+=( eo )
+MOZ_LANGS+=( es-CL )
+MOZ_LANGS+=( es-MX )
+MOZ_LANGS+=( fa )
+MOZ_LANGS+=( ff )
+MOZ_LANGS+=( gn )
+MOZ_LANGS+=( gu-IN )
+MOZ_LANGS+=( hi-IN )
+MOZ_LANGS+=( hy-AM )
+MOZ_LANGS+=( ia )
+MOZ_LANGS+=( km )
+MOZ_LANGS+=( kn )
+MOZ_LANGS+=( lij )
+MOZ_LANGS+=( mk )
+MOZ_LANGS+=( mr )
+MOZ_LANGS+=( my )
+MOZ_LANGS+=( ne-NP )
+MOZ_LANGS+=( oc )
+MOZ_LANGS+=( sco )
+MOZ_LANGS+=( si )
+MOZ_LANGS+=( son )
+MOZ_LANGS+=( szl )
+MOZ_LANGS+=( ta )
+MOZ_LANGS+=( te )
+MOZ_LANGS+=( tl )
+MOZ_LANGS+=( trs )
+MOZ_LANGS+=( ur )
+MOZ_LANGS+=( xh )
+
+mozilla_set_globals() {
+ # https://bugs.gentoo.org/587334
+ local MOZ_TOO_REGIONALIZED_FOR_L10N=(
+ fy-NL ga-IE gu-IN hi-IN hy-AM nb-NO ne-NP nn-NO pa-IN sv-SE
+ )
+
+ local lang xflag
+ for lang in "${MOZ_LANGS[@]}" ; do
+ # en and en_US are handled internally
+ if [[ ${lang} == en ]] || [[ ${lang} == en-US ]] ; then
+ continue
+ fi
+
+ # strip region subtag if $lang is in the list
+ if has ${lang} "${MOZ_TOO_REGIONALIZED_FOR_L10N[@]}" ; then
+ xflag=${lang%%-*}
+ else
+ xflag=${lang}
+ fi
+
+ SRC_URI+=" l10n_${xflag/[_@]/-}? ("
+ SRC_URI+=" ${MOZ_SRC_BASE_URI}/linux-x86_64/xpi/${lang}.xpi -> ${MOZ_P_DISTFILES}-${lang}.xpi"
+ SRC_URI+=" )"
+ IUSE+=" l10n_${xflag/[_@]/-}"
+ done
+}
+mozilla_set_globals
+
+moz_clear_vendor_checksums() {
+ debug-print-function ${FUNCNAME} "$@"
+
+ if [[ ${#} -ne 1 ]] ; then
+ die "${FUNCNAME} requires exact one argument"
+ fi
+
+ einfo "Clearing cargo checksums for ${1} ..."
+
+ sed -i \
+ -e 's/\("files":{\)[^}]*/\1/' \
+ "${S}"/third_party/rust/${1}/.cargo-checksum.json \
+ || die
+}
+
+moz_install_xpi() {
+ debug-print-function ${FUNCNAME} "$@"
+
+ if [[ ${#} -lt 2 ]] ; then
+ die "${FUNCNAME} requires at least two arguments"
+ fi
+
+ local DESTDIR=${1}
+ shift
+
+ insinto "${DESTDIR}"
+
+ local emid xpi_file xpi_tmp_dir
+ for xpi_file in "${@}" ; do
+ emid=
+ xpi_tmp_dir=$(mktemp -d --tmpdir="${T}")
+
+ # Unpack XPI
+ unzip -qq "${xpi_file}" -d "${xpi_tmp_dir}" || die
+
+ # Determine extension ID
+ if [[ -f "${xpi_tmp_dir}/install.rdf" ]] ; then
+ emid=$(sed -n -e '/install-manifest/,$ { /em:id/!d; s/.*[\">]\([^\"<>]*\)[\"<].*/\1/; p; q }' "${xpi_tmp_dir}/install.rdf")
+ [[ -z "${emid}" ]] && die "failed to determine extension id from install.rdf"
+ elif [[ -f "${xpi_tmp_dir}/manifest.json" ]] ; then
+ emid=$(sed -n -e 's/.*"id": "\([^"]*\)".*/\1/p' "${xpi_tmp_dir}/manifest.json")
+ [[ -z "${emid}" ]] && die "failed to determine extension id from manifest.json"
+ else
+ die "failed to determine extension id"
+ fi
+
+ einfo "Installing ${emid}.xpi into ${ED}${DESTDIR} ..."
+ newins "${xpi_file}" "${emid}.xpi"
+ done
+}
+
+mozconfig_add_options_ac() {
+ debug-print-function ${FUNCNAME} "$@"
+
+ if [[ ${#} -lt 2 ]] ; then
+ die "${FUNCNAME} requires at least two arguments"
+ fi
+
+ local reason=${1}
+ shift
+
+ local option
+ for option in ${@} ; do
+ echo "ac_add_options ${option} # ${reason}" >>${MOZCONFIG}
+ done
+}
+
+mozconfig_add_options_mk() {
+ debug-print-function ${FUNCNAME} "$@"
+
+ if [[ ${#} -lt 2 ]] ; then
+ die "${FUNCNAME} requires at least two arguments"
+ fi
+
+ local reason=${1}
+ shift
+
+ local option
+ for option in ${@} ; do
+ echo "mk_add_options ${option} # ${reason}" >>${MOZCONFIG}
+ done
+}
+
+mozconfig_use_enable() {
+ debug-print-function ${FUNCNAME} "$@"
+
+ if [[ ${#} -lt 1 ]] ; then
+ die "${FUNCNAME} requires at least one arguments"
+ fi
+
+ local flag=$(use_enable "${@}")
+ mozconfig_add_options_ac "$(use ${1} && echo +${1} || echo -${1})" "${flag}"
+}
+
+mozconfig_use_with() {
+ debug-print-function ${FUNCNAME} "$@"
+
+ if [[ ${#} -lt 1 ]] ; then
+ die "${FUNCNAME} requires at least one arguments"
+ fi
+
+ local flag=$(use_with "${@}")
+ mozconfig_add_options_ac "$(use ${1} && echo +${1} || echo -${1})" "${flag}"
+}
+
+pkg_pretend() {
+ if [[ ${MERGE_TYPE} != binary ]] ; then
+ if use pgo ; then
+ if ! has usersandbox $FEATURES ; then
+ die "You must enable usersandbox as X server can not run as root!"
+ fi
+ fi
+
+ # Ensure we have enough disk space to compile
+ if use pgo || use lto || use debug ; then
+ CHECKREQS_DISK_BUILD="13500M"
+ else
+ CHECKREQS_DISK_BUILD="6600M"
+ fi
+
+ check-reqs_pkg_pretend
+ fi
+}
+
+pkg_setup() {
+ if [[ ${MERGE_TYPE} != binary ]] ; then
+ if use pgo ; then
+ if ! has userpriv ${FEATURES} ; then
+ eerror "Building ${PN} with USE=pgo and FEATURES=-userpriv is not supported!"
+ fi
+ fi
+
+ # Ensure we have enough disk space to compile
+ if use pgo || use lto || use debug ; then
+ CHECKREQS_DISK_BUILD="13500M"
+ else
+ CHECKREQS_DISK_BUILD="6400M"
+ fi
+
+ check-reqs_pkg_setup
+
+ llvm_pkg_setup
+
+ if use clang && use lto ; then
+ local version_lld=$(ld.lld --version 2>/dev/null | awk '{ print $2 }')
+ [[ -n ${version_lld} ]] && version_lld=$(ver_cut 1 "${version_lld}")
+ [[ -z ${version_lld} ]] && die "Failed to read ld.lld version!"
+
+ local version_llvm_rust=$(rustc -Vv 2>/dev/null | grep -F -- 'LLVM version:' | awk '{ print $3 }')
+ [[ -n ${version_llvm_rust} ]] && version_llvm_rust=$(ver_cut 1 "${version_llvm_rust}")
+ [[ -z ${version_llvm_rust} ]] && die "Failed to read used LLVM version from rustc!"
+
+ if ver_test "${version_lld}" -ne "${version_llvm_rust}" ; then
+ eerror "Rust is using LLVM version ${version_llvm_rust} but ld.lld version belongs to LLVM version ${version_lld}."
+ eerror "You will be unable to link ${CATEGORY}/${PN}. To proceed you have the following options:"
+ eerror " - Manually switch rust version using 'eselect rust' to match used LLVM version"
+ eerror " - Switch to dev-lang/rust[system-llvm] which will guarantee matching version"
+ eerror " - Build ${CATEGORY}/${PN} without USE=lto"
+ eerror " - Rebuild lld with llvm that was used to build rust (may need to rebuild the whole "
+ eerror " llvm/clang/lld/rust chain depending on your @world updates)"
+ die "LLVM version used by Rust (${version_llvm_rust}) does not match with ld.lld version (${version_lld})!"
+ fi
+ fi
+
+ if ! use clang && [[ $(gcc-major-version) -eq 11 ]] \
+ && ! has_version -b ">sys-devel/gcc-11.1.0:11" ; then
+ # bug 792705
+ eerror "Using GCC 11 to compile firefox is currently known to be broken (see bug #792705)."
+ die "Set USE=clang or select <gcc-11 to build ${CATEGORY}/${P}."
+ fi
+
+ python-any-r1_pkg_setup
+
+ # Avoid PGO profiling problems due to enviroment leakage
+ # These should *always* be cleaned up anyway
+ unset \
+ DBUS_SESSION_BUS_ADDRESS \
+ DISPLAY \
+ ORBIT_SOCKETDIR \
+ SESSION_MANAGER \
+ XAUTHORITY \
+ XDG_CACHE_HOME \
+ XDG_SESSION_COOKIE
+
+ # Build system is using /proc/self/oom_score_adj, bug #604394
+ addpredict /proc/self/oom_score_adj
+
+ if use pgo ; then
+ # Allow access to GPU during PGO run
+ local ati_cards mesa_cards nvidia_cards render_cards
+ shopt -s nullglob
+
+ ati_cards=$(echo -n /dev/ati/card* | sed 's/ /:/g')
+ if [[ -n "${ati_cards}" ]] ; then
+ addpredict "${ati_cards}"
+ fi
+
+ mesa_cards=$(echo -n /dev/dri/card* | sed 's/ /:/g')
+ if [[ -n "${mesa_cards}" ]] ; then
+ addpredict "${mesa_cards}"
+ fi
+
+ nvidia_cards=$(echo -n /dev/nvidia* | sed 's/ /:/g')
+ if [[ -n "${nvidia_cards}" ]] ; then
+ addpredict "${nvidia_cards}"
+ fi
+
+ render_cards=$(echo -n /dev/dri/renderD128* | sed 's/ /:/g')
+ if [[ -n "${render_cards}" ]] ; then
+ addpredict "${render_cards}"
+ fi
+
+ shopt -u nullglob
+ fi
+
+ if ! mountpoint -q /dev/shm ; then
+ # If /dev/shm is not available, configure is known to fail with
+ # a traceback report referencing /usr/lib/pythonN.N/multiprocessing/synchronize.py
+ ewarn "/dev/shm is not mounted -- expect build failures!"
+ fi
+
+ # Google API keys (see http://www.chromium.org/developers/how-tos/api-keys)
+ # Note: These are for Gentoo Linux use ONLY. For your own distribution, please
+ # get your own set of keys.
+ if [[ -z "${MOZ_API_KEY_GOOGLE+set}" ]] ; then
+ MOZ_API_KEY_GOOGLE="AIzaSyDEAOvatFogGaPi0eTgsV_ZlEzx0ObmepsMzfAc"
+ fi
+
+ if [[ -z "${MOZ_API_KEY_LOCATION+set}" ]] ; then
+ MOZ_API_KEY_LOCATION="AIzaSyB2h2OuRgGaPicUgy5N-5hsZqiPW6sH3n_rptiQ"
+ fi
+
+ # Mozilla API keys (see https://location.services.mozilla.com/api)
+ # Note: These are for Gentoo Linux use ONLY. For your own distribution, please
+ # get your own set of keys.
+ if [[ -z "${MOZ_API_KEY_MOZILLA+set}" ]] ; then
+ MOZ_API_KEY_MOZILLA="edb3d487-3a84-46m0ap1e3-9dfd-92b5efaaa005"
+ fi
+
+ # Ensure we use C locale when building, bug #746215
+ export LC_ALL=C
+ fi
+
+ CONFIG_CHECK="~SECCOMP"
+ WARNING_SECCOMP="CONFIG_SECCOMP not set! This system will be unable to play DRM-protected content."
+ linux-info_pkg_setup
+}
+
+src_unpack() {
+ local _lp_dir="${WORKDIR}/language_packs"
+ local _src_file
+
+ if [[ ! -d "${_lp_dir}" ]] ; then
+ mkdir "${_lp_dir}" || die
+ fi
+
+ for _src_file in ${A} ; do
+ if [[ ${_src_file} == *.xpi ]]; then
+ cp "${DISTDIR}/${_src_file}" "${_lp_dir}" || die "Failed to copy '${_src_file}' to '${_lp_dir}'!"
+ else
+ unpack ${_src_file}
+ fi
+ done
+}
+
+src_prepare() {
+ use lto && rm -v "${WORKDIR}"/firefox-patches/*-LTO-Only-enable-LTO-*.patch
+ eapply "${WORKDIR}/firefox-patches"
+ # riscv support from https://github.com/makotokato/gecko-dev
+ eapply "${FILESDIR}/firefox-riscv64-support.patch"
+ # disable cargo-vet check in order to do ./mach vendor rust
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=1787601
+ # skip check_macroassembler_style.py
+ eapply "${FILESDIR}/firefox-riscv64-hack.patch"
+
+ # Allow user to apply any additional patches without modifing ebuild
+ eapply_user
+
+ # Make cargo respect MAKEOPTS
+ export CARGO_BUILD_JOBS="$(makeopts_jobs)"
+
+ # Make LTO respect MAKEOPTS
+ sed -i \
+ -e "s/multiprocessing.cpu_count()/$(makeopts_jobs)/" \
+ "${S}"/build/moz.configure/lto-pgo.configure \
+ || die "sed failed to set num_cores"
+
+ # Make ICU respect MAKEOPTS
+ sed -i \
+ -e "s/multiprocessing.cpu_count()/$(makeopts_jobs)/" \
+ "${S}"/intl/icu_sources_data.py \
+ || die "sed failed to set num_cores"
+
+ # sed-in toolchain prefix
+ sed -i \
+ -e "s/objdump/${CHOST}-objdump/" \
+ "${S}"/python/mozbuild/mozbuild/configure/check_debug_ranges.py \
+ || die "sed failed to set toolchain prefix"
+
+ sed -i \
+ -e 's/ccache_stats = None/return None/' \
+ "${S}"/python/mozbuild/mozbuild/controller/building.py \
+ || die "sed failed to disable ccache stats call"
+
+ einfo "Removing pre-built binaries ..."
+ find "${S}"/third_party -type f \( -name '*.so' -o -name '*.o' \) -print -delete || die
+
+ # Clearing checksums where we have applied patches
+ moz_clear_vendor_checksums audioipc
+ moz_clear_vendor_checksums audioipc-client
+ moz_clear_vendor_checksums audioipc-server
+
+ # Create build dir
+ BUILD_DIR="${WORKDIR}/${PN}_build"
+ mkdir -p "${BUILD_DIR}" || die
+
+ # Write API keys to disk
+ echo -n "${MOZ_API_KEY_GOOGLE//gGaPi/}" > "${S}"/api-google.key || die
+ echo -n "${MOZ_API_KEY_LOCATION//gGaPi/}" > "${S}"/api-location.key || die
+ echo -n "${MOZ_API_KEY_MOZILLA//m0ap1/}" > "${S}"/api-mozilla.key || die
+
+ xdg_environment_reset
+}
+
+src_configure() {
+ # Show flags set at the beginning
+ einfo "Current BINDGEN_CFLAGS:\t${BINDGEN_CFLAGS:-no value set}"
+ einfo "Current CFLAGS:\t\t${CFLAGS:-no value set}"
+ einfo "Current CXXFLAGS:\t\t${CXXFLAGS:-no value set}"
+ einfo "Current LDFLAGS:\t\t${LDFLAGS:-no value set}"
+ einfo "Current RUSTFLAGS:\t\t${RUSTFLAGS:-no value set}"
+
+ local have_switched_compiler=
+ if use clang && ! tc-is-clang ; then
+ # Force clang
+ einfo "Enforcing the use of clang due to USE=clang ..."
+ have_switched_compiler=yes
+ AR=llvm-ar
+ AS=llvm-as
+ CC=${CHOST}-clang
+ CXX=${CHOST}-clang++
+ NM=llvm-nm
+ RANLIB=llvm-ranlib
+ elif ! use clang && ! tc-is-gcc ; then
+ # Force gcc
+ have_switched_compiler=yes
+ einfo "Enforcing the use of gcc due to USE=-clang ..."
+ AR=gcc-ar
+ CC=${CHOST}-gcc
+ CXX=${CHOST}-g++
+ NM=gcc-nm
+ RANLIB=gcc-ranlib
+ fi
+
+ if [[ -n "${have_switched_compiler}" ]] ; then
+ # Because we switched active compiler we have to ensure
+ # that no unsupported flags are set
+ strip-unsupported-flags
+ fi
+
+ # Ensure we use correct toolchain
+ export HOST_CC="$(tc-getBUILD_CC)"
+ export HOST_CXX="$(tc-getBUILD_CXX)"
+ tc-export CC CXX LD AR NM OBJDUMP RANLIB PKG_CONFIG
+
+ # Pass the correct toolchain paths through cbindgen
+ if tc-is-cross-compiler ; then
+ export BINDGEN_CFLAGS="${SYSROOT:+--sysroot=${ESYSROOT}} --target=${CHOST} ${BINDGEN_CFLAGS-}"
+ fi
+
+ # Set MOZILLA_FIVE_HOME
+ export MOZILLA_FIVE_HOME="/usr/$(get_libdir)/${PN}"
+
+ # python/mach/mach/mixin/process.py fails to detect SHELL
+ export SHELL="${EPREFIX}/bin/bash"
+
+ # Set state path
+ export MOZBUILD_STATE_PATH="${BUILD_DIR}"
+
+ # Set MOZCONFIG
+ export MOZCONFIG="${S}/.mozconfig"
+
+ # Initialize MOZCONFIG
+ mozconfig_add_options_ac '' --enable-application=browser
+
+ # Set Gentoo defaults
+ export MOZILLA_OFFICIAL=1
+
+ mozconfig_add_options_ac 'Gentoo default' \
+ --allow-addon-sideload \
+ --disable-cargo-incremental \
+ --disable-crashreporter \
+ --disable-gpsd \
+ --disable-install-strip \
+ --disable-parental-controls \
+ --disable-strip \
+ --disable-updater \
+ --enable-negotiateauth \
+ --enable-new-pass-manager \
+ --enable-official-branding \
+ --enable-release \
+ --enable-system-ffi \
+ --enable-system-pixman \
+ --host="${CBUILD:-${CHOST}}" \
+ --libdir="${EPREFIX}/usr/$(get_libdir)" \
+ --prefix="${EPREFIX}/usr" \
+ --target="${CHOST}" \
+ --without-ccache \
+ --without-wasm-sandboxed-libraries \
+ --with-intl-api \
+ --with-libclang-path="$(llvm-config --libdir)" \
+ --with-system-nspr \
+ --with-system-nss \
+ --with-system-zlib \
+ --with-toolchain-prefix="${CHOST}-" \
+ --with-unsigned-addon-scopes=app,system \
+ --x-includes="${ESYSROOT}/usr/include" \
+ --x-libraries="${ESYSROOT}/usr/$(get_libdir)"
+
+ # Set update channel
+ local update_channel=release
+ [[ -n ${MOZ_ESR} ]] && update_channel=esr
+ mozconfig_add_options_ac '' --update-channel=${update_channel}
+
+ if ! use x86 && [[ ${CHOST} != armv*h* ]] ; then
+ mozconfig_add_options_ac '' --enable-rust-simd
+ fi
+
+ # 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 || use riscv; then
+ mozconfig_add_options_ac '' --disable-sandbox
+ else
+ mozconfig_add_options_ac '' --enable-sandbox
+ fi
+ if use riscv; then
+ mozconfig_add_options_ac '' --disable-jit
+ fi
+
+ if [[ -s "${S}/api-google.key" ]] ; then
+ local key_origin="Gentoo default"
+ if [[ $(cat "${S}/api-google.key" | md5sum | awk '{ print $1 }') != 709560c02f94b41f9ad2c49207be6c54 ]] ; then
+ key_origin="User value"
+ fi
+
+ mozconfig_add_options_ac "${key_origin}" \
+ --with-google-safebrowsing-api-keyfile="${S}/api-google.key"
+ else
+ einfo "Building without Google API key ..."
+ fi
+
+ if [[ -s "${S}/api-location.key" ]] ; then
+ local key_origin="Gentoo default"
+ if [[ $(cat "${S}/api-location.key" | md5sum | awk '{ print $1 }') != ffb7895e35dedf832eb1c5d420ac7420 ]] ; then
+ key_origin="User value"
+ fi
+
+ mozconfig_add_options_ac "${key_origin}" \
+ --with-google-location-service-api-keyfile="${S}/api-location.key"
+ else
+ einfo "Building without Location API key ..."
+ fi
+
+ if [[ -s "${S}/api-mozilla.key" ]] ; then
+ local key_origin="Gentoo default"
+ if [[ $(cat "${S}/api-mozilla.key" | md5sum | awk '{ print $1 }') != 3927726e9442a8e8fa0e46ccc39caa27 ]] ; then
+ key_origin="User value"
+ fi
+
+ mozconfig_add_options_ac "${key_origin}" \
+ --with-mozilla-api-keyfile="${S}/api-mozilla.key"
+ else
+ einfo "Building without Mozilla API key ..."
+ fi
+
+ mozconfig_use_with system-av1
+ mozconfig_use_with system-harfbuzz
+ mozconfig_use_with system-harfbuzz system-graphite2
+ mozconfig_use_with system-icu
+ mozconfig_use_with system-jpeg
+ mozconfig_use_with system-libevent
+ mozconfig_use_with system-libvpx
+ mozconfig_use_with system-png
+ mozconfig_use_with system-webp
+
+ mozconfig_use_enable dbus
+ mozconfig_use_enable libproxy
+
+ use eme-free && mozconfig_add_options_ac '+eme-free' --disable-eme
+
+ mozconfig_use_enable geckodriver
+
+ if use hardened ; then
+ mozconfig_add_options_ac "+hardened" --enable-hardening
+ append-ldflags "-Wl,-z,relro -Wl,-z,now"
+ fi
+
+ local myaudiobackends=""
+ use jack && myaudiobackends+="jack,"
+ use sndio && myaudiobackends+="sndio,"
+ use pulseaudio && myaudiobackends+="pulseaudio,"
+ ! use pulseaudio && myaudiobackends+="alsa,"
+
+ mozconfig_add_options_ac '--enable-audio-backends' --enable-audio-backends="${myaudiobackends::-1}"
+
+ mozconfig_use_enable wifi necko-wifi
+
+ if use X && use wayland ; then
+ mozconfig_add_options_ac '+x11+wayland' --enable-default-toolkit=cairo-gtk3-x11-wayland
+ elif ! use X && use wayland ; then
+ mozconfig_add_options_ac '+wayland' --enable-default-toolkit=cairo-gtk3-wayland-only
+ else
+ mozconfig_add_options_ac '+x11' --enable-default-toolkit=cairo-gtk3
+ fi
+
+ if use lto ; then
+ if use clang ; then
+ # Upstream only supports lld when using clang
+ mozconfig_add_options_ac "forcing ld=lld due to USE=clang and USE=lto" --enable-linker=lld
+
+ mozconfig_add_options_ac '+lto' --enable-lto=cross
+
+ else
+ # ThinLTO is currently broken, see bmo#1644409
+ mozconfig_add_options_ac '+lto' --enable-lto=full
+ mozconfig_add_options_ac "linker is set to bfd" --enable-linker=bfd
+ fi
+
+ if use pgo ; then
+ mozconfig_add_options_ac '+pgo' MOZ_PGO=1
+
+ if use clang ; then
+ # Used in build/pgo/profileserver.py
+ export LLVM_PROFDATA="llvm-profdata"
+ fi
+ fi
+ else
+ # Avoid auto-magic on linker
+ if use clang ; then
+ # This is upstream's default
+ mozconfig_add_options_ac "forcing ld=lld due to USE=clang" --enable-linker=lld
+ else
+ mozconfig_add_options_ac "linker is set to bfd" --enable-linker=bfd
+ fi
+ fi
+
+ # LTO flag was handled via configure
+ filter-flags '-flto*'
+
+ mozconfig_use_enable debug
+ if use debug ; then
+ mozconfig_add_options_ac '+debug' --disable-optimize
+ else
+ if is-flag '-g*' ; then
+ if use clang ; then
+ mozconfig_add_options_ac 'from CFLAGS' --enable-debug-symbols=$(get-flag '-g*')
+ else
+ mozconfig_add_options_ac 'from CFLAGS' --enable-debug-symbols
+ fi
+ else
+ mozconfig_add_options_ac 'Gentoo default' --disable-debug-symbols
+ fi
+
+ if is-flag '-O0' ; then
+ mozconfig_add_options_ac "from CFLAGS" --enable-optimize=-O0
+ elif is-flag '-O4' ; then
+ mozconfig_add_options_ac "from CFLAGS" --enable-optimize=-O4
+ elif is-flag '-O3' ; then
+ mozconfig_add_options_ac "from CFLAGS" --enable-optimize=-O3
+ elif is-flag '-O1' ; then
+ mozconfig_add_options_ac "from CFLAGS" --enable-optimize=-O1
+ elif is-flag '-Os' ; then
+ mozconfig_add_options_ac "from CFLAGS" --enable-optimize=-Os
+ else
+ mozconfig_add_options_ac "Gentoo default" --enable-optimize=-O2
+ fi
+ fi
+
+ # Debug flag was handled via configure
+ filter-flags '-g*'
+
+ # Optimization flag was handled via configure
+ filter-flags '-O*'
+
+ # Modifications to better support ARM, bug #553364
+ if use cpu_flags_arm_neon ; then
+ mozconfig_add_options_ac '+cpu_flags_arm_neon' --with-fpu=neon
+
+ if ! tc-is-clang ; then
+ # thumb options aren't supported when using clang, bug 666966
+ mozconfig_add_options_ac '+cpu_flags_arm_neon' \
+ --with-thumb=yes \
+ --with-thumb-interwork=no
+ fi
+ fi
+
+ if [[ ${CHOST} == armv*h* ]] ; then
+ mozconfig_add_options_ac 'CHOST=armv*h*' --with-float-abi=hard
+
+ if ! use system-libvpx ; then
+ sed -i \
+ -e "s|softfp|hard|" \
+ "${S}"/media/libvpx/moz.build \
+ || die
+ fi
+ fi
+
+ if use clang ; then
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=1482204
+ # https://bugzilla.mozilla.org/show_bug.cgi?id=1483822
+ # toolkit/moz.configure Elfhack section: target.cpu in ('arm', 'x86', 'x86_64')
+ local disable_elf_hack=
+ if use amd64 ; then
+ disable_elf_hack=yes
+ elif use x86 ; then
+ disable_elf_hack=yes
+ elif use arm ; then
+ disable_elf_hack=yes
+ fi
+
+ if [[ -n ${disable_elf_hack} ]] ; then
+ mozconfig_add_options_ac 'elf-hack is broken when using Clang' --disable-elf-hack
+ fi
+ elif tc-is-gcc ; then
+ if ver_test $(gcc-fullversion) -ge 10 ; then
+ einfo "Forcing -fno-tree-loop-vectorize to workaround GCC bug, see bug 758446 ..."
+ append-cxxflags -fno-tree-loop-vectorize
+ fi
+ fi
+
+ # Additional ARCH support
+ case "${ARCH}" in
+ arm)
+ # Reduce the memory requirements for linking
+ if use clang ; then
+ # Nothing to do
+ :;
+ elif use lto ; then
+ append-ldflags -Wl,--no-keep-memory
+ else
+ append-ldflags -Wl,--no-keep-memory -Wl,--reduce-memory-overheads
+ fi
+ ;;
+ esac
+
+ if ! use elibc_glibc ; then
+ mozconfig_add_options_ac '!elibc_glibc' --disable-jemalloc
+ fi
+
+ # Allow elfhack to work in combination with unstripped binaries
+ # when they would normally be larger than 2GiB.
+ append-ldflags "-Wl,--compress-debug-sections=zlib"
+
+ # Make revdep-rebuild.sh happy; Also required for musl
+ append-ldflags -Wl,-rpath="${MOZILLA_FIVE_HOME}",--enable-new-dtags
+
+ # Pass $MAKEOPTS to build system
+ export MOZ_MAKE_FLAGS="${MAKEOPTS}"
+
+ # Use system's Python environment
+ PIP_NETWORK_INSTALL_RESTRICTED_VIRTUALENVS=mach
+
+ if use system-python-libs; then
+ export MACH_BUILD_PYTHON_NATIVE_PACKAGE_SOURCE="system"
+ else
+ export MACH_BUILD_PYTHON_NATIVE_PACKAGE_SOURCE="none"
+ fi
+
+ # Disable notification when build system has finished
+ export MOZ_NOSPAM=1
+
+ # Portage sets XARGS environment variable to "xargs -r" by default which
+ # breaks build system's check_prog() function which doesn't support arguments
+ mozconfig_add_options_ac 'Gentoo default' "XARGS=${EPREFIX}/usr/bin/xargs"
+
+ # Set build dir
+ mozconfig_add_options_mk 'Gentoo default' "MOZ_OBJDIR=${BUILD_DIR}"
+
+ # Show flags we will use
+ einfo "Build BINDGEN_CFLAGS:\t${BINDGEN_CFLAGS:-no value set}"
+ einfo "Build CFLAGS:\t\t${CFLAGS:-no value set}"
+ einfo "Build CXXFLAGS:\t\t${CXXFLAGS:-no value set}"
+ einfo "Build LDFLAGS:\t\t${LDFLAGS:-no value set}"
+ einfo "Build RUSTFLAGS:\t\t${RUSTFLAGS:-no value set}"
+
+ # Handle EXTRA_CONF and show summary
+ local ac opt hash reason
+
+ # Apply EXTRA_ECONF entries to $MOZCONFIG
+ if [[ -n ${EXTRA_ECONF} ]] ; then
+ IFS=\! read -a ac <<<${EXTRA_ECONF// --/\!}
+ for opt in "${ac[@]}"; do
+ mozconfig_add_options_ac "EXTRA_ECONF" --${opt#--}
+ done
+ fi
+
+ echo
+ echo "=========================================================="
+ echo "Building ${PF} with the following configuration"
+ grep ^ac_add_options "${MOZCONFIG}" | while read ac opt hash reason; do
+ [[ -z ${hash} || ${hash} == \# ]] \
+ || die "error reading mozconfig: ${ac} ${opt} ${hash} ${reason}"
+ printf " %-30s %s\n" "${opt}" "${reason:-mozilla.org default}"
+ done
+ echo "=========================================================="
+ echo
+
+ # To avoid huge patches of rust library (~200MB), we have to download on the fly
+ einfo "riscv overlay: Performing ./mach vendor rust to update third party libs"
+ ./mach vendor rust --ignore-modified || die
+ ./mach configure || die
+}
+
+src_compile() {
+ local virtx_cmd=
+
+ if use pgo ; then
+ virtx_cmd=virtx
+
+ # Reset and cleanup environment variables used by GNOME/XDG
+ gnome2_environment_reset
+
+ addpredict /root
+ fi
+
+ if ! use X && use wayland; then
+ local -x GDK_BACKEND=wayland
+ else
+ local -x GDK_BACKEND=x11
+ fi
+
+ ${virtx_cmd} ./mach build --verbose \
+ || die
+}
+
+src_install() {
+ # xpcshell is getting called during install
+ pax-mark m \
+ "${BUILD_DIR}"/dist/bin/xpcshell \
+ "${BUILD_DIR}"/dist/bin/${PN} \
+ "${BUILD_DIR}"/dist/bin/plugin-container
+
+ DESTDIR="${D}" ./mach install || die
+
+ # Upstream cannot ship symlink but we can (bmo#658850)
+ rm "${ED}${MOZILLA_FIVE_HOME}/${PN}-bin" || die
+ dosym ${PN} ${MOZILLA_FIVE_HOME}/${PN}-bin
+
+ # Don't install llvm-symbolizer from sys-devel/llvm package
+ if [[ -f "${ED}${MOZILLA_FIVE_HOME}/llvm-symbolizer" ]] ; then
+ rm -v "${ED}${MOZILLA_FIVE_HOME}/llvm-symbolizer" || die
+ fi
+
+ # Install policy (currently only used to disable application updates)
+ insinto "${MOZILLA_FIVE_HOME}/distribution"
+ newins "${FILESDIR}"/distribution.ini distribution.ini
+ newins "${FILESDIR}"/disable-auto-update.policy.json policies.json
+
+ # Install system-wide preferences
+ local PREFS_DIR="${MOZILLA_FIVE_HOME}/browser/defaults/preferences"
+ insinto "${PREFS_DIR}"
+ newins "${FILESDIR}"/gentoo-default-prefs.js gentoo-prefs.js
+
+ local GENTOO_PREFS="${ED}${PREFS_DIR}/gentoo-prefs.js"
+
+ # Set dictionary path to use system hunspell
+ cat >>"${GENTOO_PREFS}" <<-EOF || die "failed to set spellchecker.dictionary_path pref"
+ pref("spellchecker.dictionary_path", "${EPREFIX}/usr/share/myspell");
+ EOF
+
+ # Force hwaccel prefs if USE=hwaccel is enabled
+ if use hwaccel ; then
+ cat "${FILESDIR}"/gentoo-hwaccel-prefs.js-r2 \
+ >>"${GENTOO_PREFS}" \
+ || die "failed to add prefs to force hardware-accelerated rendering to all-gentoo.js"
+
+ if use wayland; then
+ cat >>"${GENTOO_PREFS}" <<-EOF || die "failed to set hwaccel wayland prefs"
+ pref("gfx.x11-egl.force-enabled", false);
+ EOF
+ else
+ cat >>"${GENTOO_PREFS}" <<-EOF || die "failed to set hwaccel x11 prefs"
+ pref("gfx.x11-egl.force-enabled", true);
+ EOF
+ fi
+ fi
+
+ if ! use gmp-autoupdate ; then
+ local plugin
+ for plugin in "${MOZ_GMP_PLUGIN_LIST[@]}" ; do
+ einfo "Disabling auto-update for ${plugin} plugin ..."
+ cat >>"${GENTOO_PREFS}" <<-EOF || die "failed to disable autoupdate for ${plugin} media plugin"
+ pref("media.${plugin}.autoupdate", false);
+ EOF
+ done
+ fi
+
+ # Force the graphite pref if USE=system-harfbuzz is enabled, since the pref cannot disable it
+ if use system-harfbuzz ; then
+ cat >>"${GENTOO_PREFS}" <<-EOF || die "failed to set gfx.font_rendering.graphite.enabled pref"
+ sticky_pref("gfx.font_rendering.graphite.enabled", true);
+ EOF
+ fi
+
+ # Install language packs
+ local langpacks=( $(find "${WORKDIR}/language_packs" -type f -name '*.xpi') )
+ if [[ -n "${langpacks}" ]] ; then
+ moz_install_xpi "${MOZILLA_FIVE_HOME}/distribution/extensions" "${langpacks[@]}"
+ fi
+
+ # Install geckodriver
+ if use geckodriver ; then
+ einfo "Installing geckodriver into ${ED}${MOZILLA_FIVE_HOME} ..."
+ pax-mark m "${BUILD_DIR}"/dist/bin/geckodriver
+ exeinto "${MOZILLA_FIVE_HOME}"
+ doexe "${BUILD_DIR}"/dist/bin/geckodriver
+
+ dosym ${MOZILLA_FIVE_HOME}/geckodriver /usr/bin/geckodriver
+ fi
+
+ # Install icons
+ local icon_srcdir="${S}/browser/branding/official"
+ local icon_symbolic_file="${FILESDIR}/icon/firefox-symbolic.svg"
+
+ insinto /usr/share/icons/hicolor/symbolic/apps
+ newins "${icon_symbolic_file}" ${PN}-symbolic.svg
+
+ local icon size
+ for icon in "${icon_srcdir}"/default*.png ; do
+ size=${icon%.png}
+ size=${size##*/default}
+
+ if [[ ${size} -eq 48 ]] ; then
+ newicon "${icon}" ${PN}.png
+ fi
+
+ newicon -s ${size} "${icon}" ${PN}.png
+ done
+
+ # Install menu
+ local app_name="Mozilla ${MOZ_PN^}"
+ local desktop_file="${FILESDIR}/icon/${PN}-r3.desktop"
+ local desktop_filename="${PN}.desktop"
+ local exec_command="${PN}"
+ local icon="${PN}"
+ local use_wayland="false"
+
+ if use wayland ; then
+ use_wayland="true"
+ fi
+
+ cp "${desktop_file}" "${WORKDIR}/${PN}.desktop-template" || die
+
+ sed -i \
+ -e "s:@NAME@:${app_name}:" \
+ -e "s:@EXEC@:${exec_command}:" \
+ -e "s:@ICON@:${icon}:" \
+ "${WORKDIR}/${PN}.desktop-template" \
+ || die
+
+ newmenu "${WORKDIR}/${PN}.desktop-template" "${desktop_filename}"
+
+ rm "${WORKDIR}/${PN}.desktop-template" || die
+
+ # Install wrapper script
+ [[ -f "${ED}/usr/bin/${PN}" ]] && rm "${ED}/usr/bin/${PN}"
+ newbin "${FILESDIR}/${PN}-r1.sh" ${PN}
+
+ # Update wrapper
+ sed -i \
+ -e "s:@PREFIX@:${EPREFIX}/usr:" \
+ -e "s:@MOZ_FIVE_HOME@:${MOZILLA_FIVE_HOME}:" \
+ -e "s:@APULSELIB_DIR@:${apulselib}:" \
+ -e "s:@DEFAULT_WAYLAND@:${use_wayland}:" \
+ "${ED}/usr/bin/${PN}" \
+ || die
+}
+
+pkg_preinst() {
+ xdg_pkg_preinst
+
+ # If the apulse libs are available in MOZILLA_FIVE_HOME then apulse
+ # does not need to be forced into the LD_LIBRARY_PATH
+ if use pulseaudio && has_version ">=media-sound/apulse-0.1.12-r4" ; then
+ einfo "APULSE found; Generating library symlinks for sound support ..."
+ local lib
+ pushd "${ED}${MOZILLA_FIVE_HOME}" &>/dev/null || die
+ for lib in ../apulse/libpulse{.so{,.0},-simple.so{,.0}} ; do
+ # A quickpkg rolled by hand will grab symlinks as part of the package,
+ # so we need to avoid creating them if they already exist.
+ if [[ ! -L ${lib##*/} ]] ; then
+ ln -s "${lib}" ${lib##*/} || die
+ fi
+ done
+ popd &>/dev/null || die
+ fi
+}
+
+pkg_postinst() {
+ xdg_pkg_postinst
+
+ if ! use gmp-autoupdate ; then
+ elog "USE='-gmp-autoupdate' has disabled the following plugins from updating or"
+ elog "installing into new profiles:"
+ local plugin
+ for plugin in "${MOZ_GMP_PLUGIN_LIST[@]}" ; do
+ elog "\t ${plugin}"
+ done
+ elog
+ fi
+
+ if use pulseaudio && has_version ">=media-sound/apulse-0.1.12-r4" ; then
+ elog "Apulse was detected at merge time on this system and so it will always be"
+ elog "used for sound. If you wish to use pulseaudio instead please unmerge"
+ elog "media-sound/apulse."
+ elog
+ fi
+
+ local show_doh_information
+ local show_normandy_information
+ local show_shortcut_information
+
+ if [[ -z "${REPLACING_VERSIONS}" ]] ; then
+ # New install; Tell user that DoH is disabled by default
+ show_doh_information=yes
+ show_normandy_information=yes
+ show_shortcut_information=no
+ else
+ local replacing_version
+ for replacing_version in ${REPLACING_VERSIONS} ; do
+ if ver_test "${replacing_version}" -lt 91.0 ; then
+ # Tell user that we no longer install a shortcut
+ # per supported display protocol
+ show_shortcut_information=yes
+ fi
+ done
+ fi
+
+ if [[ -n "${show_doh_information}" ]] ; then
+ elog
+ elog "Note regarding Trusted Recursive Resolver aka DNS-over-HTTPS (DoH):"
+ elog "Due to privacy concerns (encrypting DNS might be a good thing, sending all"
+ elog "DNS traffic to Cloudflare by default is not a good idea and applications"
+ elog "should respect OS configured settings), \"network.trr.mode\" was set to 5"
+ elog "(\"Off by choice\") by default."
+ elog "You can enable DNS-over-HTTPS in ${PN^}'s preferences."
+ fi
+
+ # bug 713782
+ if [[ -n "${show_normandy_information}" ]] ; then
+ elog
+ elog "Upstream operates a service named Normandy which allows Mozilla to"
+ elog "push changes for default settings or even install new add-ons remotely."
+ elog "While this can be useful to address problems like 'Armagadd-on 2.0' or"
+ elog "revert previous decisions to disable TLS 1.0/1.1, privacy and security"
+ elog "concerns prevail, which is why we have switched off the use of this"
+ elog "service by default."
+ elog
+ elog "To re-enable this service set"
+ elog
+ elog " app.normandy.enabled=true"
+ elog
+ elog "in about:config."
+ fi
+
+ if [[ -n "${show_shortcut_information}" ]] ; then
+ elog
+ elog "Since ${PN}-91.0 we no longer install multiple shortcuts for"
+ elog "each supported display protocol. Instead we will only install"
+ elog "one generic Mozilla ${PN^} shortcut."
+ elog "If you still want to be able to select between running Mozilla ${PN^}"
+ elog "on X11 or Wayland, you have to re-create these shortcuts on your own."
+ fi
+
+ # bug 835078
+ if use hwaccel && has_version "x11-drivers/xf86-video-nouveau"; then
+ ewarn "You have nouveau drivers installed in your system and 'hwaccel' "
+ ewarn "enabled for Firefox. Nouveau / your GPU might not support the "
+ ewarn "required EGL, so either disable 'hwaccel' or try the workaround "
+ ewarn "explained in https://bugs.gentoo.org/835078#c5 if Firefox crashes."
+ fi
+
+ elog
+ elog "Unfortunately Firefox-100.0 breaks compatibility with some sites using "
+ elog "useragent checks. To temporarily fix this, enter about:config and modify "
+ elog "network.http.useragent.forceVersion preference to \"99\"."
+ elog "Or install an addon to change your useragent."
+ elog "See: https://support.mozilla.org/en-US/kb/difficulties-opening-or-using-website-firefox-100"
+ elog
+}
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2022-08-31 2:30 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-08-31 2:30 [gentoo-commits] proj/riscv:master commit in: www-client/firefox/files/, www-client/firefox/ Yixun Lan
-- strict thread matches above, loose matches on Subject: below --
2022-04-20 13:23 Yixun Lan
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox